<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Vitor Enes on Vitor Enes</title>
    <link>/</link>
    <description>Recent content in Vitor Enes on Vitor Enes</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 18 Nov 2022 00:00:00 +0000</lastBuildDate>
    <atom:link href="/" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Planet-Scale Leaderless Consensus</title>
      <link>/publication/phd-thesis/</link>
      <pubDate>Fri, 18 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>/publication/phd-thesis/</guid>
      <description></description>
    </item>
    
    <item>
      <title>Efficient Replication via Timestamp Stability</title>
      <link>/publication/enes-tempo/</link>
      <pubDate>Tue, 27 Apr 2021 00:00:00 +0100</pubDate>
      
      <guid>/publication/enes-tempo/</guid>
      <description></description>
    </item>
    
    <item>
      <title>State-Machine Replication for Planet-Scale Systems</title>
      <link>/publication/enes-atlas/</link>
      <pubDate>Wed, 29 Apr 2020 00:00:00 +0100</pubDate>
      
      <guid>/publication/enes-atlas/</guid>
      <description></description>
    </item>
    
    <item>
      <title>Paxos Made Wrong (part I)</title>
      <link>/post/2020/03/paxos-made-wrong-part-i/</link>
      <pubDate>Wed, 18 Mar 2020 19:45:00 +0000</pubDate>
      
      <guid>/post/2020/03/paxos-made-wrong-part-i/</guid>
      <description>

&lt;p&gt;In each blog post of this series, I will present a modification of Paxos, together with a sequence of protocol messages, that will lead to an invariant violation.
Hopefully this will lead to a better understanding of Paxos (mine and yours).&lt;/p&gt;

&lt;h3 id=&#34;on-a-quest-for-understanding&#34;&gt;On a quest for understanding&lt;/h3&gt;

&lt;p&gt;Maybe it&amp;rsquo;s just me, but I often gain intuition on why a &lt;strong&gt;protocol&lt;/strong&gt; works with situations where it doesn&amp;rsquo;t.
A way to do that, is to change one step of the protocol (e.g. change a comparison from $&amp;gt;$ to $\leq$ or reduce the size of a quorum by 1) and see what happens.&lt;/p&gt;

&lt;p&gt;These protocol modifications typically lead to an &lt;strong&gt;invariant&lt;/strong&gt; violation (e.g. processes disagree on the consensus value).
Then, when examining this misbehavior, we can gain more intuition on why that protocol step had to be the way it was.
The more we do this, the more understanding we build, and at some point, we will have a pretty good grasp of what&amp;rsquo;s going on.&lt;/p&gt;

&lt;p&gt;If the modification doesn&amp;rsquo;t lead to an invariant violation and the protocol remains correct&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, then maybe the protocol is unnecessarily strict and there might be room for improvement.
&lt;a href=&#34;https://fpaxos.github.io/&#34; target=&#34;_blank&#34;&gt;Flexible Paxos&lt;/a&gt; reminds me exactly of that: a rigid requirement in Paxos that, when lifted, opened the door to new optimizations.
(To be clear, I&amp;rsquo;m not saying this is how it happened.)&lt;/p&gt;

&lt;h3 id=&#34;mutation-testing&#34;&gt;Mutation testing&lt;/h3&gt;

&lt;p&gt;In a way, this is similar to &lt;a href=&#34;https://en.wikipedia.org/wiki/Mutation_testing&#34; target=&#34;_blank&#34;&gt;mutation testing&lt;/a&gt; but with a different goal.
&lt;!-- _(WARNING: I&#39;ve never used a mutation testing framework, so what follows might make little sense.)_ --&gt;
In mutation testing, the program suffers mutations to check the quality of tests: if after the mutation the test still passes, then it&amp;rsquo;s not a good test, and we should improve it.&lt;/p&gt;

&lt;p&gt;In our case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the mutated program is &lt;strong&gt;the protocol&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;the tests validate &lt;strong&gt;the protocol invariants&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;but the goal is not to improve the tests&lt;/li&gt;
&lt;li&gt;instead, &lt;strong&gt;a failing test&lt;/strong&gt; &amp;ndash; in our case, an invariant that &lt;em&gt;didn&amp;rsquo;t&lt;/em&gt; hold &amp;ndash; &lt;strong&gt;will help us understand the protocol a bit better&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;with a passing test &amp;ndash; in our case, an invariant that &lt;em&gt;did&lt;/em&gt; hold &amp;ndash; we may be on our way to an optimization &amp;ndash; yay! (this is unlikely and won&amp;rsquo;t be the goal)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;the-tests-validate-the-protocol-invariants&#34;&gt;&amp;ldquo;The tests validate the protocol invariants&amp;rdquo;&lt;/h3&gt;

&lt;p&gt;To better understand this, let&amp;rsquo;s think about unit tests.
Typically a unit test will have a setup, run some program logic, and in the end check that everything went well.
&lt;strong&gt;These checks in the end are the protocol invariants&lt;/strong&gt;.
&lt;strong&gt;But we still need the setup and the program logic to be executed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As an example on what I mean by setup and program logic in the context of distributed protocols, let&amp;rsquo;s think about Paxos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the setup would be the number of processes $n$ and the number of allowed faults $f$&lt;/li&gt;
&lt;li&gt;the program logic would be the set of messages that are exchanged between processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With something like &lt;a href=&#34;https://propertesting.com/&#34; target=&#34;_blank&#34;&gt;property testing&lt;/a&gt;, the testing framework can generate the setup and protocol messages for us.
Then, for each test case generated, the framework checks some &lt;em&gt;property&lt;/em&gt;. In our case, this property would be a protocol invariant.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not planning to, but I may need to resort to property testing if at some point I&amp;rsquo;m unable to generate an example with a failing invariant.
Nevertheless, it doesn&amp;rsquo;t matter where the example comes from, as long as it helps building intuition, ultimately leading to a full understanding.&lt;/p&gt;

&lt;h3 id=&#34;what-s-next&#34;&gt;What&amp;rsquo;s next&lt;/h3&gt;

&lt;p&gt;In the next blog post I will probably start with a specification of Paxos that we can modify in later posts.&lt;/p&gt;

&lt;p&gt;Before any parting words, I would like to thank Cláudia Brito (&lt;a href=&#34;https://twitter.com/cbrito_18&#34; target=&#34;_blank&#34;&gt;@cbrito_18&lt;/a&gt;) and Rogério Pontes (&lt;a href=&#34;https://twitter.com/rogerio_acp&#34; target=&#34;_blank&#34;&gt;@rogerio_acp&lt;/a&gt;) for their feedback on earlier versions of this post.&lt;/p&gt;

&lt;p&gt;Until next time. Stay safe!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;Knowing that some protocol change maintains correctness is a more complex topic. My go-to option would be adapting previous pen-and-paper proofs and existing TLA+ models.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:1&#34;&gt;&lt;sup&gt;^&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Fault-tolerant Causal Stability (part I)</title>
      <link>/post/2019/07/fault-tolerant-causal-stability-part-i/</link>
      <pubDate>Mon, 22 Jul 2019 00:00:00 +0100</pubDate>
      
      <guid>/post/2019/07/fault-tolerant-causal-stability-part-i/</guid>
      <description>

&lt;p&gt;You guessed it! This post shows that &lt;strong&gt;1) causal stability is not fault-tolerant&lt;/strong&gt; but &lt;strong&gt;2) we can do something about it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Well, that was the intention, &lt;em&gt;at least&lt;/em&gt;.
The blog post was becoming too long, so I&amp;rsquo;ll divide it in (exactly those) two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;part I&lt;/strong&gt;: revisits the concepts of causal consistency and causal stability; we&amp;rsquo;ll also discuss how these two concepts can be implemented in a simple way; we&amp;rsquo;ll conclude that causal stability is not fault-tolerant&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;part II&lt;/strong&gt;: shows that causal stability &lt;em&gt;can be&lt;/em&gt; fault-tolerant and &lt;span class=&#34;markup-quote&#34;&gt;the level of fault-tolerance provided simply depends on the size of the write quorum&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;causal-consistency&#34;&gt;Causal Consistency&lt;/h3&gt;

&lt;p&gt;In simple terms, causal consistency ensures that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;if&lt;/strong&gt; operation $o$ causes operation $p$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;then&lt;/strong&gt; every process in the system will not observe $p$ without observing $o$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, &lt;strong&gt;no effect is observed without its cause&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Figure 1&lt;/strong&gt; we have an example where causal consistency is not respected.
We start two objects $x$ and $y$ initialized at $0$.
Alice writes $x = 1$ and then $y = 2$.
At this point, in a causally consistent system, Bob can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$x = 0 \land y = 0$&lt;/li&gt;
&lt;li&gt;$x = 1 \land y = 0$&lt;/li&gt;
&lt;li&gt;$x = 1 \land y = 2$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, it ended up reading $x = 0 \land y = 2$ (i.e. it saw the second write by Alice without seeing the first), and with that, the run in &lt;strong&gt;Figure 1&lt;/strong&gt; is not causally consistent.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/1-causality-violation.jpg&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;A run that is not causally consistency.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h4 id=&#34;implementing-causal-consistency&#34;&gt;Implementing causal consistency&lt;/h4&gt;

&lt;p&gt;We can implement a causally consistent system with two simple steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;attach to each operation $o$ a set containing all its preceding operations; let&amp;rsquo;s call this set &lt;em&gt;the dependencies of&lt;/em&gt; $o$ and denote it by $\textsf{dep}[o]$&lt;/li&gt;
&lt;li&gt;execute $o$ once all operations in $\textsf{dep}[o]$ have been executed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Note how this fixes the problem presented in &lt;strong&gt;Figure 1&lt;/strong&gt;.)&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s also denote the set of executed operations by $\textsf{Executed}$.&lt;/p&gt;

&lt;p&gt;If the process submits operation $o$, then the dependencies of $o$ will be the set of operations that have been executed at that moment, i.e. $\textsf{dep}(o) = \textsf{Executed}$.&lt;/p&gt;

&lt;h4 id=&#34;a-note-on-concurrency&#34;&gt;A note on concurrency&lt;/h4&gt;

&lt;p&gt;If operation $o$ causes operation $p$, then $o$ is part of the set of dependencies of $p$:&lt;/p&gt;

&lt;p&gt;$$o \in \textsf{dep}(p)$$&lt;/p&gt;

&lt;p&gt;However, it can happen that $o$ doesn&amp;rsquo;t cause $p$ and $p$ doesn&amp;rsquo;t cause $o$.&lt;br /&gt;
When this is the case, we say that $o$ and $p$ are &lt;strong&gt;concurrent&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;$$o \not \in \textsf{dep}(p) \land p \not \in \textsf{dep}(o)$$&lt;/p&gt;

&lt;h3 id=&#34;causal-stability&#34;&gt;Causal Stability&lt;/h3&gt;

&lt;p&gt;An operation $o$ is causally stable (denoted by $\textsf{stable}(o)$) if every operation $p$ that will be executed in the system must be caused by $o$:&lt;/p&gt;

&lt;p&gt;$$\textsf{stable}(o) \equiv \forall p \cdot p \not \in \textsf{Executed} \implies o \in \textsf{dep}(p)$$&lt;/p&gt;

&lt;p&gt;In other words, if $\textsf{stable}(o)$ then every operation will be in the future of $o$.&lt;/p&gt;

&lt;div class=&#34;alert alert-note&#34;&gt;
  &lt;div&gt;
    The concept of causal stability is exploited, for example, by &lt;a href=&#34;https://hal.archives-ouvertes.fr/inria-00555588/&#34; target=&#34;_blank&#34;&gt;CRDTs (Section 4.1)&lt;/a&gt; to perform &lt;a href=&#34;https://arxiv.org/abs/1710.04469&#34; target=&#34;_blank&#34;&gt;garbage-collection (Section 7.2)&lt;/a&gt;.
  &lt;/div&gt;
&lt;/div&gt;

&lt;h4 id=&#34;getting-some-intuition-with-an-example&#34;&gt;Getting some intuition with an example&lt;/h4&gt;

&lt;p&gt;Let&amp;rsquo;s pause for a bit with an example where we compute the set of stable operations.&lt;/p&gt;

&lt;p&gt;In this example we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 processes: &lt;strong&gt;a&lt;/strong&gt;, &lt;strong&gt;b&lt;/strong&gt; and &lt;strong&gt;c&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;4 operations: $o$, $p$, $q$ and $r$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;rsquo;s say that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a&lt;/strong&gt; submitted $o$ and then $p$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;b&lt;/strong&gt; saw $o$ and $p$, and then submitted $q$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;c&lt;/strong&gt; saw $o$ and submitted $r$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we have the following $\textsf{Executed}$:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$\textsf{Executed}_{\textbf{a}} = \{o, p\}$&lt;/li&gt;
&lt;li&gt;$\textsf{Executed}_{\textbf{b}} = \{o, p, q\}$&lt;/li&gt;
&lt;li&gt;$\textsf{Executed}_{\textbf{c}} = \{o, r\}$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recall that: &lt;em&gt;the set of dependencies of an operation is the set of executed operations at the time the operation is submitted&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So at this point we know that any operation submitted (by any process) will include $o$ as a dependency. &lt;strong&gt;This means that $o$ is stable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can&amp;rsquo;t say the same about any of the remaining operations.&lt;/p&gt;

&lt;h4 id=&#34;implementing-causal-stability&#34;&gt;Implementing causal stability&lt;/h4&gt;

&lt;p&gt;Let&amp;rsquo;s denote the set of all processes in the system by $\mathcal{I}$.&lt;/p&gt;

&lt;p&gt;Stability can be detected if we learn&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; what&amp;rsquo;s been executed by each process, i.e. we know $\textsf{Executed}_i$ for every process $i \in \mathcal{I}$.&lt;/p&gt;

&lt;p&gt;Then, the set of stable operations is given by the intersection of all $\textsf{Executed}_i$&amp;rsquo;s:&lt;/p&gt;

&lt;p&gt;$$\bigcap_{i \in \mathcal{I}} \textsf{Executed}_i$$&lt;/p&gt;

&lt;h4 id=&#34;a-second-note-on-concurrency&#34;&gt;A (second) note on concurrency&lt;/h4&gt;

&lt;p&gt;Given operation $o$, $\textsf{stable}(o)$ implies that all operations concurrent with $o$ have also been executed.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s see why that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for some operation $p$ be concurrent with $o$, then $o$ can&amp;rsquo;t be a dependency of $p$: $o \not \in \textsf{dep}(p)$&lt;/li&gt;
&lt;li&gt;however, this contradicts $\textsf{stable}(o)$ that requires  that $o$ is a dependency of &lt;em&gt;every&lt;/em&gt; operation that will be executed, and in particular, that it is a dependency of $p$: $o \in \textsf{dep}(p)$.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;causal-stability-is-a-local-property&#34;&gt;Causal stability is a local property&lt;/h4&gt;

&lt;p&gt;What&amp;rsquo;s stable on one process might not (yet) be stable on other processes.&lt;/p&gt;

&lt;p&gt;This is because processes compute stability based on what they know others have executed, and different processes might have different views on what&amp;rsquo;s been executed.&lt;/p&gt;

&lt;p&gt;However, if an operation is stable on some process, it will &lt;em&gt;eventually&lt;/em&gt; become stable on every process.&lt;/p&gt;

&lt;h3 id=&#34;not-so-fault-tolerant-causal-stability&#34;&gt;(Not-so-fault-tolerant) Causal Stability&lt;/h3&gt;

&lt;p&gt;At this point, we already know why causal stability is not fault-tolerant.&lt;/p&gt;

&lt;p&gt;In order to advance stability, processes need to learn what &lt;strong&gt;all&lt;/strong&gt; processes are executing, and if some process crashes, the set of stable operations will &lt;em&gt;not&lt;/em&gt; grow. And &lt;strong&gt;that&amp;rsquo;s not fault-tolerant&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So in &lt;strong&gt;part II&lt;/strong&gt; we&amp;rsquo;ll try to fix that!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;span class=&#34;markup-quote&#34;&gt;UPDATE:&lt;/span&gt;&lt;/strong&gt; I&amp;rsquo;ll address the concerns raised in the replies to my &lt;a href=&#34;https://twitter.com/vitorenesduarte/status/1153329830957604865&#34; target=&#34;_blank&#34;&gt;tweet&lt;/a&gt; in the next blog post.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;This can be implemented, for example, by having processes periodically broadcasting what they have executed.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:1&#34;&gt;&lt;sup&gt;^&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Efficient Synchronization of State-based CRDTs</title>
      <link>/post/2019/04/efficient-sync/</link>
      <pubDate>Tue, 16 Apr 2019 00:00:00 +0100</pubDate>
      
      <guid>/post/2019/04/efficient-sync/</guid>
      <description>

&lt;!-- *__[(click here to skip to the CRDT stuff)](#context)__* --&gt;

&lt;!-- ### Preface --&gt;

&lt;p&gt;This week I was at ICDE&amp;rsquo;19 where I presented &lt;strong&gt;Efficient Synchronization of State-based CRDTs&lt;/strong&gt; &lt;a href=&#34;/publication/enes-efficient-synchronization/&#34;&gt;(here&amp;rsquo;s a link to paper and slides)&lt;/a&gt;.
&lt;!-- The conference was held in the Parisian Hotel in Macau, a really shiny/fancy place [(just a glimpse)](https://www.instagram.com/p/Bv9KXYhBIgs/). --&gt;
&lt;!-- Not everything looks like this in Macau, and I was fortunate enough to see some of its other faces. --&gt;
&lt;!-- And me being Portuguese made it all much more fun, I imagine. --&gt;
&lt;!--  --&gt;
&lt;!-- I&#39;m currently[^1] at the airport, with 6h to kill until the 12-hour flight to Munich, and a few hours later, the 3-hour flight to Porto. --&gt;
&lt;!-- With this, I guess I have no excuse to not do a bit of writing. --&gt;
Following &lt;a href=&#34;https://ordepdev.me/posts/diving-into-merkle-trees&#34; target=&#34;_blank&#34;&gt;Pedro&amp;rsquo;s idea&lt;/a&gt;, and since the talk is still fresh, this post will be a transcript of it.&lt;/p&gt;

&lt;!-- [^1]: I mean, when I started writing this. --&gt;

&lt;h3 id=&#34;context&#34;&gt;Context&lt;/h3&gt;

&lt;p&gt;In Figure 1, I briefly explain the CRDT acronym. My &lt;a href=&#34;/post/2019/04/genuine-vs-artificial/&#34;&gt;previous post&lt;/a&gt; was just about that.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/1-crdt.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Conflict-free Replicated Data Types.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;outline&#34;&gt;Outline&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CRDT variants&lt;/strong&gt;: First, we&amp;rsquo;ll take a look CRDT synchronization models. The main variants are &lt;strong&gt;operation-based&lt;/strong&gt; and &lt;strong&gt;state-based&lt;/strong&gt;. There&amp;rsquo;s also &lt;strong&gt;delta-based&lt;/strong&gt;, that is a variant of state-based synchronization.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;From &lt;em&gt;filter&lt;/em&gt; to &lt;em&gt;decomposition; filter; join&lt;/em&gt;&lt;/strong&gt;: In classic delta-based, when a replica receives a delta, it checks whether this delta &lt;strong&gt;has something new&lt;/strong&gt; (the &lt;strong&gt;filter&lt;/strong&gt;), and if it has, the delta is propagated to the peers in the system.
We&amp;rsquo;ll show that this is insufficient, and a more sophisticated approach is necessary: replicas should instead decompose the delta (the &lt;strong&gt;decomposition&lt;/strong&gt;), select the relevant parts (the &lt;strong&gt;filter&lt;/strong&gt;), and then merge them back together (the &lt;strong&gt;join&lt;/strong&gt;), effectively &lt;strong&gt;extracting what&amp;rsquo;s new&lt;/strong&gt; in the received delta.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A super-realistic example of &lt;em&gt;decomposition; filter; join&lt;/em&gt;:&lt;/strong&gt;
Consider a wedding cake.
When we decompose it, we get all the layers.
Then, we decide that we just want the first and the third layer.
In the end, we glue the interesting layers back together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decomposition of state-based CRDTs&lt;/strong&gt;: The &lt;strong&gt;filter&lt;/strong&gt; and &lt;strong&gt;join&lt;/strong&gt; operations are already part of the CRDT framework. We&amp;rsquo;ll see how they look like in the simplest CRDT (a &lt;strong&gt;grow-only set&lt;/strong&gt;).
Then, we&amp;rsquo;ll introduce the missing part (the &lt;strong&gt;decomposition&lt;/strong&gt;) and the three properties that define &amp;ldquo;good&amp;rdquo; decompositions.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;And finally, some &lt;strong&gt;experimental results&lt;/strong&gt; before we go.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;figure&gt;

&lt;img src=&#34;img/2-outline.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;The outline of the talk.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;crdt-synchronization-models&#34;&gt;CRDT synchronization models&lt;/h3&gt;

&lt;p&gt;Two of the main differences between CRDTs synchronization models are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;guarantees&lt;/strong&gt; that the synchronization &lt;strong&gt;middleware&lt;/strong&gt; should provide&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;payload&lt;/strong&gt; exchanged between replicas upon a new update&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;operation-based&#34;&gt;Operation-based&lt;/h4&gt;

&lt;p&gt;In the operation-based model, the middleware should provide &lt;strong&gt;exactly-once causal delivery&lt;/strong&gt; of operations (which can be expensive).
&lt;strong&gt;The upside&lt;/strong&gt;: only the update &lt;strong&gt;operation&lt;/strong&gt; (typically small) needs to be sent.&lt;/p&gt;

&lt;h4 id=&#34;state-based&#34;&gt;State-based&lt;/h4&gt;

&lt;p&gt;In the state-based model, messages can be &lt;strong&gt;dropped&lt;/strong&gt;, &lt;strong&gt;reordered&lt;/strong&gt; and &lt;strong&gt;duplicated&lt;/strong&gt;, meaning no expensive middleware is required in state-based.
&lt;strong&gt;The downside&lt;/strong&gt;: the &lt;strong&gt;full CRDT state&lt;/strong&gt; needs to be sent when synchronizing replicas.&lt;/p&gt;

&lt;h4 id=&#34;delta-state-based&#34;&gt;Delta-state-based&lt;/h4&gt;

&lt;p&gt;Delta-state-based promises to be &lt;strong&gt;the best of both worlds&lt;/strong&gt; by inheriting the middleware guarantees from state-based (i.e. none), and by exchanging &lt;strong&gt;deltas&lt;/strong&gt; that are typically as small as operations.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/3-variants.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Different CRDT variants (i.e. synchronization models).&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;but-in-reality&#34;&gt;But in reality&amp;hellip;&lt;/h3&gt;

&lt;p&gt;There are inefficiencies in the delta-based synchronization model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In terms of &lt;strong&gt;bandwidth&lt;/strong&gt; (LHS of Figure 4), delta-based can be &lt;strong&gt;as expensive as state-based&lt;/strong&gt; (i.e., effectively sending the full state on every synchronization).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;And since large states are being exchanged, trying to compute these deltas results in a &lt;strong&gt;substantial CPU overhead&lt;/strong&gt;, when comparing to state-based (RHS of Figure 4).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;figure&gt;

&lt;img src=&#34;img/4-reality.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Delta-based can be as bad as state-based in terms of bandwidth, while incurring a substantial CPU overhead.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;so-in-this-paper&#34;&gt;So, in this paper&amp;hellip;&lt;/h3&gt;




&lt;figure&gt;

&lt;img src=&#34;img/5-contribution.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Our main contribution.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;state-based-crdts&#34;&gt;State-based CRDTs&lt;/h3&gt;

&lt;p&gt;As I promised above, we&amp;rsquo;ll explore the ideas behind the paper resorting to the &lt;strong&gt;simplest CRDT that exists: a set&lt;/strong&gt;.
And from sets, we&amp;rsquo;ll just need two binary operations: &lt;strong&gt;subset&lt;/strong&gt; and &lt;strong&gt;set union&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I mentioned before that all CRDTs have a &lt;strong&gt;filter&lt;/strong&gt; and a &lt;strong&gt;join&lt;/strong&gt; operation. For sets, &lt;em&gt;the filter is the subset&lt;/em&gt;, while &lt;em&gt;the join is the set union&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&#34;state-based-vs-delta-based&#34;&gt;State-based vs Delta-based&lt;/h4&gt;

&lt;p&gt;State-based CRDTs define functions that allow us to update the CRDT state. These are called &lt;strong&gt;mutators&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, delta-based CRDTs define &lt;strong&gt;delta-mutators&lt;/strong&gt; that returns &lt;strong&gt;deltas&lt;/strong&gt;.
We can think of these deltas as the &lt;strong&gt;state difference between the state before the update and the state after&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As an example, if we&amp;rsquo;re trying to add the element &lt;strong&gt;c&lt;/strong&gt; to a set that contains &lt;strong&gt;a&lt;/strong&gt; and &lt;strong&gt;b&lt;/strong&gt; (i.e., &lt;strong&gt;{a, b}&lt;/strong&gt;), the mutator will return the set &lt;strong&gt;{a, b, c}&lt;/strong&gt;, while the delta-mutator simply returns the delta &lt;strong&gt;{c}&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This delta is then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;joined with the local state&lt;/strong&gt; resorting to join operation (in this case, the set union); after this step, &lt;em&gt;the local state is the same as it would have been if the mutator was used&lt;/em&gt; (in our example, we would get &lt;strong&gt;{a, b, c}&lt;/strong&gt;)&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;added to a delta-buffer&lt;/strong&gt; that contains deltas to be propagated to peers&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;figure&gt;

&lt;img src=&#34;img/6-state-based.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;State-based CRDTs define mutators while delta-based CRDTs define delta-mutators.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;introducing-some-notation-before-an-example&#34;&gt;Introducing some notation before an example&lt;/h3&gt;

&lt;p&gt;On the &lt;strong&gt;right&lt;/strong&gt; of our replica, we&amp;rsquo;ll depict the current &lt;strong&gt;CRDT state&lt;/strong&gt; (an empty set in Figure 7). At the &lt;strong&gt;bottom&lt;/strong&gt;, we&amp;rsquo;ll have the current list of deltas in the &lt;strong&gt;delta-buffer&lt;/strong&gt; (an empty delta-buffer in Figure 7).&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/7-notation.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Delta-buffer notation: on the right, the CRDT state; at the bottom, the delta-buffer.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;the-problem-with-the-classic-delta-propagation&#34;&gt;The problem with the classic delta propagation&lt;/h3&gt;

&lt;p&gt;Consider the example in Figure 8 with four replicas, &lt;strong&gt;A&lt;/strong&gt;, &lt;strong&gt;B&lt;/strong&gt;, &lt;strong&gt;C&lt;/strong&gt;, and &lt;strong&gt;D&lt;/strong&gt;.
All replicas start with an empty set and an empty delta-buffer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When &lt;strong&gt;A&lt;/strong&gt; adds the element &lt;strong&gt;x&lt;/strong&gt; to the set, the delta-mutator produces the delta &lt;strong&gt;{x}&lt;/strong&gt;.
This delta is joined with the local state (that becomes &lt;strong&gt;{x}&lt;/strong&gt;, since union of &lt;strong&gt;{ }&lt;/strong&gt; with &lt;strong&gt;{x}&lt;/strong&gt; is &lt;strong&gt;{x}&lt;/strong&gt;), and it is added to the delta-buffer.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt; synchronizes with &lt;strong&gt;C&lt;/strong&gt; by sending the new deltas in the delta-buffer (i.e. just &lt;strong&gt;{x}&lt;/strong&gt;).
When &lt;strong&gt;C&lt;/strong&gt; receives this delta, it joins it with the local state and also adds the delta to its delta-buffer, so that this delta can be further propagated.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;C&lt;/strong&gt; syncs with &lt;strong&gt;D&lt;/strong&gt; (the process is similar to the one above).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Now &lt;strong&gt;A&lt;/strong&gt; adds element &lt;strong&gt;y&lt;/strong&gt; to the set. The resulting delta, &lt;strong&gt;{y}&lt;/strong&gt;, is joined with the local state (that becomes &lt;strong&gt;{x, y}&lt;/strong&gt;) and added to the delta-buffer.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt; syncs with &lt;strong&gt;B&lt;/strong&gt; by sending the join of all the deltas never sent to &lt;strong&gt;B&lt;/strong&gt; (i.e. &lt;strong&gt;{x, y}&lt;/strong&gt;).
&lt;strong&gt;B&lt;/strong&gt; does the standard thing when receiving the delta.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;B&lt;/strong&gt; syncs with &lt;strong&gt;C&lt;/strong&gt; and &lt;span class=&#34;markup-quote&#34;&gt;now we get to the interesting part&lt;/span&gt;.
Recall that the local state of &lt;strong&gt;C&lt;/strong&gt; before receiving this delta from &lt;strong&gt;B&lt;/strong&gt; is &lt;strong&gt;{x}&lt;/strong&gt;.
Although I didn&amp;rsquo;t mentioned yet in this running example, in the outline of the talk we&amp;rsquo;ve seen that when a delta is received, a &lt;strong&gt;filter&lt;/strong&gt; occurs: when &lt;strong&gt;C&lt;/strong&gt; receives &lt;strong&gt;{x, y}&lt;/strong&gt;, it checks whether this delta has something new (compared to the local state).
And indeed, there is something new (element &lt;strong&gt;y&lt;/strong&gt;)!
Since there&amp;rsquo;s something new, the delta is joined with the local state and added to the delta-buffer.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;And finally, &lt;strong&gt;C&lt;/strong&gt; syncs with &lt;strong&gt;D&lt;/strong&gt; by sending the new delta in its delta-buffer (i.e. &lt;strong&gt;{x, y}&lt;/strong&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;figure&gt;

&lt;img src=&#34;img/8-delta-buffer.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;A distributed execution of classic delta-based synchronization showing an inefficiency in delta propagation.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;p&gt;The last step is problematic because &lt;strong&gt;C&lt;/strong&gt; sends &lt;strong&gt;{x, y}&lt;/strong&gt; to &lt;strong&gt;D&lt;/strong&gt;, even though in its previous sync step with &lt;strong&gt;D&lt;/strong&gt; it sent &lt;strong&gt;{x}&lt;/strong&gt;.
We would expect that now it would send the new state changes, i.e. only &lt;strong&gt;{y}&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This shows that the simple filter done by &lt;strong&gt;C&lt;/strong&gt; when it received &lt;strong&gt;{x, y}&lt;/strong&gt; is not enough!
Instead, &lt;strong&gt;C&lt;/strong&gt; must decompose the received delta &lt;strong&gt;{x, y}&lt;/strong&gt;, select/filter the interesting bits, join them back together, and only then, add what results (that should be &lt;strong&gt;{y}&lt;/strong&gt;) to the delta-buffer.&lt;/p&gt;

&lt;p&gt;We already know the &lt;strong&gt;filter&lt;/strong&gt; and &lt;strong&gt;join&lt;/strong&gt; operation (at least for sets).
Let&amp;rsquo;s now see how we do the &lt;strong&gt;decomposition&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;decomposition-of-state-based-crdts&#34;&gt;Decomposition of state-based CRDTs&lt;/h3&gt;

&lt;p&gt;In Figure 9 we have a decomposition example: given the set &lt;strong&gt;{a, b, c}&lt;/strong&gt;, the decomposition of this set should be &lt;strong&gt;{{a}, {b}, {c}}&lt;/strong&gt;&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In the paper, we define three properties, that when respected, produce &amp;ldquo;good&amp;rdquo; decompositions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;The join everything in the decomposition produces the original element.&lt;/em&gt; As an example, &lt;strong&gt;{{b}, {c}}&lt;/strong&gt; is not a good decomposition because its join only produces &lt;strong&gt;{b, c}&lt;/strong&gt;, and not &lt;strong&gt;{a, b, c}&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;All elements in the decomposition are needed.&lt;/em&gt; &lt;strong&gt;{{a, b}, {b}, {c}}&lt;/strong&gt; is not a good decomposition because &lt;strong&gt;{b}&lt;/strong&gt; is not needed to produce &lt;strong&gt;{a, b, c}&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;No element can be further decomposed.&lt;/em&gt; &lt;strong&gt;{{a, b}, {c}}&lt;/strong&gt;  is not a good decomposition because one of its elements, namely &lt;strong&gt;{a, b}&lt;/strong&gt;, can be further decomposed into &lt;strong&gt;{a}&lt;/strong&gt; and &lt;strong&gt;{b}&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Only the decomposition &lt;strong&gt;{{a}, {b}, {c}}&lt;/strong&gt; respects all three properties.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/9-decomposition.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Example decomposition and the three properties of good decompositions.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;p&gt;(In the paper we show that for all states of CRDTs used in practice, &lt;strong&gt;a decomposition always exists&lt;/strong&gt;, and furthermore, &lt;strong&gt;this decomposition is unique&lt;/strong&gt;.)&lt;/p&gt;

&lt;h3 id=&#34;introducing-the-crdt-difference-operation&#34;&gt;Introducing the CRDT-difference operation&lt;/h3&gt;

&lt;p&gt;Once we have a decomposition, now we can build a &lt;strong&gt;CRDT-difference binary operation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For sets, this operation boils down to the &lt;a href=&#34;http://mathworld.wolfram.com/SetDifference.html&#34; target=&#34;_blank&#34;&gt;set difference&lt;/a&gt; that can be simply defined as:&lt;/p&gt;

&lt;p&gt;$$ a \setminus b = \{ x \in a \mid x \not \in b \}$$&lt;/p&gt;

&lt;p&gt;As an example (from Figure 10), the difference between &lt;strong&gt;{x, y}&lt;/strong&gt; and &lt;strong&gt;{x}&lt;/strong&gt; is &lt;strong&gt;{y}&lt;/strong&gt; (i.e. &lt;strong&gt;{x, y}&lt;/strong&gt;$\setminus$&lt;strong&gt;{x} = {y}&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;This operation can be generalized for CRDTs resorting to the decomposition we&amp;rsquo;ve just introduced.
We don&amp;rsquo;t need to worry much about the formula in Figure 10, but the general idea is the following: for each element &lt;strong&gt;x&lt;/strong&gt; in the decomposition of the first argument (i.e. &lt;strong&gt;a&lt;/strong&gt;), we check whether that &lt;strong&gt;x&lt;/strong&gt; &amp;ldquo;is needed&amp;rdquo; in the second argument (i.e. &lt;strong&gt;b&lt;/strong&gt;) resorting to the filter operation; in the end, we join all &lt;strong&gt;x&lt;/strong&gt; that passed the filter, in order to obtain the final CRDT state difference.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/10-difference.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;A new binary operation for CRDTs.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;going-back-to-our-example&#34;&gt;Going back to our example&lt;/h3&gt;

&lt;p&gt;Now we&amp;rsquo;re ready to &amp;ldquo;fix&amp;rdquo; our example.&lt;/p&gt;

&lt;p&gt;When &lt;strong&gt;C&lt;/strong&gt; receives &lt;strong&gt;{x, y}&lt;/strong&gt; from &lt;strong&gt;B&lt;/strong&gt;, instead of checking if &lt;strong&gt;{x, y}&lt;/strong&gt; has anything new, it computes the difference between the received delta &lt;strong&gt;{x, y}&lt;/strong&gt; and its local state &lt;strong&gt;{x}&lt;/strong&gt;.
This returns only the new pieces of information in the received delta, i.e. simply &lt;strong&gt;{y}&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The returned &lt;strong&gt;{y}&lt;/strong&gt; is added to the delta-buffer, and now the last sync step is exactly what we expected: only &lt;strong&gt;{y}&lt;/strong&gt; is sent from &lt;strong&gt;C&lt;/strong&gt; to &lt;strong&gt;D&lt;/strong&gt;.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/11-delta-buffer-rr.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Solving the inefficiency with the difference operation.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;p&gt;Since the replica receiving the delta, &lt;em&gt;removes redundant state in the received delta&lt;/em&gt;, we denote this optimization by &lt;strong&gt;RR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that this problem only occurred because &lt;strong&gt;C&lt;/strong&gt; received the same piece of information (&lt;strong&gt;{x}&lt;/strong&gt;) from two different replicas: both from &lt;strong&gt;A&lt;/strong&gt; and from &lt;strong&gt;B&lt;/strong&gt;.
This means that we have a &lt;strong&gt;cycle&lt;/strong&gt; in the network topology (this will be relevant in the experimental evaluation).&lt;/p&gt;

&lt;h3 id=&#34;a-very-simple-optimization&#34;&gt;A very simple optimization&lt;/h3&gt;

&lt;p&gt;In Figure 12 we have depicted another problem in delta propagation: &lt;strong&gt;A&lt;/strong&gt; produced a delta (by adding an element to the set), sent this delta to &lt;strong&gt;B&lt;/strong&gt;, and &lt;strong&gt;B&lt;/strong&gt; sent this delta back to &lt;strong&gt;A&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This behavior is undesirable but fortunately it is &lt;strong&gt;super simple to fix&lt;/strong&gt;.
Each delta in the delta-buffer should be tagged with its origin (in the example, &lt;strong&gt;B&lt;/strong&gt; would tag &lt;strong&gt;{x}&lt;/strong&gt; with &lt;strong&gt;A&lt;/strong&gt;), and never sent back to the origin in the next sync steps.
This optimization is denoted by &lt;strong&gt;BP&lt;/strong&gt; given that replicas should &lt;em&gt;avoid back-propagation of received deltas&lt;/em&gt;.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/12-delta-buffer-bp.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Avoiding back-propagation of deltas.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;evaluation&#34;&gt;Evaluation&lt;/h3&gt;

&lt;p&gt;This post is already becoming super long, so let&amp;rsquo;s now try to finish it quickly.&lt;/p&gt;

&lt;p&gt;As we&amp;rsquo;ve seen before, cycles in the network topology might result in redundant state being propagated between replicas. With that, in the evaluation we wanted to &lt;strong&gt;observe the behavior of the different synchronization models with and without cycles in the topology&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For that, we ran experiments with a &lt;strong&gt;tree&lt;/strong&gt; (acyclic) and a &lt;strong&gt;partial-mesh&lt;/strong&gt; (cyclic).
Both these topologies are depicted in Figure 13.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/13-micro-setup.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;The two network topologies used in the experiments: tree and partial-mesh.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h4 id=&#34;set-micro-benchmark&#34;&gt;Set micro-benchmark&lt;/h4&gt;

&lt;p&gt;In Figure 14 we have the bandwidth required by &lt;strong&gt;state-based&lt;/strong&gt;, &lt;strong&gt;delta-based&lt;/strong&gt;, &lt;strong&gt;delta-based BP&lt;/strong&gt;, &lt;strong&gt;delta-based RR&lt;/strong&gt;, and &lt;strong&gt;delta-based BP+RR&lt;/strong&gt;, when synchronizing a replicated set.
The results with the tree are on the left, and the results with the partial-mesh are on the right.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If we look at the first two bars, we can see that vanilla delta-based represents no improvement when compared to state-based, independently of the topology employed.&lt;/li&gt;
&lt;li&gt;The third and fourth bars reveal something interesting: &lt;strong&gt;RR&lt;/strong&gt; is only required when the topology has cycles, since &lt;strong&gt;BP&lt;/strong&gt; alone achieves the best result (&lt;strong&gt;BP+RR&lt;/strong&gt;) in the acyclic topology.&lt;/li&gt;
&lt;/ul&gt;




&lt;figure&gt;

&lt;img src=&#34;img/14-micro-results.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Bandwidth results from the set micro-benchmark.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;you-may-be-wondering-what-s-difficult-about-that&#34;&gt;You may be wondering what&amp;rsquo;s difficult about that!?!?&lt;/h3&gt;

&lt;p&gt;For sets, this looks super simple. And I really hope that&amp;rsquo;s indeed the case, since this was the goal.
However, all of this generalizes for any CRDT, as long as we know how to decompose them.&lt;/p&gt;

&lt;p&gt;An excerpt from the last appendix in the paper:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this section we show that for each composition technique there is a corresponding decomposition rule. As the lattice join ⊔ of a composite CRDT is defined in terms of the lattice join of its components [35], decomposition rules of a composite CRDT follow the same idea and resort to the decomposition of its smaller parts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can find such rules in Figure 15.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/15-sets-are-easy.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;The decomposition rule of each composition technique.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;

&lt;h3 id=&#34;there-s-much-more-in-the-paper&#34;&gt;There&amp;rsquo;s much more in the paper&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;On the experimental side&lt;/strong&gt; we have other micro-benchmarks (&lt;strong&gt;counter&lt;/strong&gt; and &lt;strong&gt;map&lt;/strong&gt;), comparisons with &lt;strong&gt;operation-based CRDTs&lt;/strong&gt; and two variants of the &lt;strong&gt;Scuttlebutt&lt;/strong&gt; algorithm, and a &lt;strong&gt;Retwis&lt;/strong&gt; benchmark&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;On the theory side&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resorting to the CRDT-difference operation, now we know what &lt;strong&gt;optimal delta-mutators&lt;/strong&gt; should return (optimal in the sense that they return the smallest delta)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&#34;markup-quote&#34;&gt;State-based CRDTs are not only join-semilattices, they are lattices, and even more than that, they are distributive lattices!!!&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;figure&gt;

&lt;img src=&#34;img/16-paper.png&#34; /&gt;


&lt;/figure&gt;

&lt;h3 id=&#34;the-end&#34;&gt;The end&lt;/h3&gt;

&lt;p&gt;I hope you&amp;rsquo;ve enjoyed this transcript, and that it didn&amp;rsquo;t end up being too dense.
This paper has also been covered by &lt;a href=&#34;https://blog.acolyer.org/2019/03/11/efficient-synchronisation-of-state-based-crdts/&#34; target=&#34;_blank&#34;&gt;The Morning Paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If any question comes up, don&amp;rsquo;t hesitate!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:2&#34;&gt;This is basically a &lt;a href=&#34;https://en.wikipedia.org/wiki/Partition_of_a_set&#34; target=&#34;_blank&#34;&gt;set partition&lt;/a&gt; with a further restriction (property 3) on the possible elements in the partition.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:2&#34;&gt;&lt;sup&gt;^&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Genuine vs Artificial Conflict-freeness</title>
      <link>/post/2019/04/genuine-vs-artificial/</link>
      <pubDate>Sat, 13 Apr 2019 00:00:00 +0100</pubDate>
      
      <guid>/post/2019/04/genuine-vs-artificial/</guid>
      <description>

&lt;p&gt;This blog post started with me trying to write a transcript of the talk I gave at ICDE&amp;rsquo;19 this week on &lt;strong&gt;Efficient Synchronization of State-based CRDTs&lt;/strong&gt;. Soon after, it derailed in this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;span class=&#34;markup-quote&#34;&gt;UPDATE:&lt;/span&gt;&lt;/strong&gt; The full transcript of the talk can now be found &lt;a href=&#34;/post/2019/04/efficient-sync/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;figure&gt;

&lt;img src=&#34;img/1-crdt.png&#34; /&gt;


&lt;/figure&gt;

&lt;p&gt;The figure above was my first slide, where I attempted to explain the CRDT acronym. From right to left:&lt;/p&gt;

&lt;h4 id=&#34;data-types&#34;&gt;Data Types&lt;/h4&gt;

&lt;p&gt;In CRDTs, the &lt;strong&gt;abstraction&lt;/strong&gt; is richer than simply reading and writing &lt;strong&gt;registers&lt;/strong&gt;:
we can increment/decrement &lt;strong&gt;counters&lt;/strong&gt;, add/remove elements to/from &lt;strong&gt;sets&lt;/strong&gt;, and so on&amp;hellip;&lt;/p&gt;

&lt;h4 id=&#34;replicated&#34;&gt;Replicated&lt;/h4&gt;

&lt;p&gt;This is not specific to CRDTs. We replicate for &lt;strong&gt;quality of service&lt;/strong&gt;.
For example, with users across the globe, if we deploy replicas also across the globe, we can have &lt;strong&gt;low&lt;/strong&gt; latency when accessing data.
Also, if some replica is unavailable, users can &lt;strong&gt;fail-over&lt;/strong&gt; to another close-by replica.&lt;/p&gt;

&lt;h4 id=&#34;conflict-free&#34;&gt;Conflict-free&lt;/h4&gt;

&lt;p&gt;Recall the &lt;a href=&#34;https://en.wikipedia.org/wiki/PACELC_theorem&#34; target=&#34;_blank&#34;&gt;PACELC theorem&lt;/a&gt;: if we have a network &lt;strong&gt;P&lt;/strong&gt;artition, we must pick between &lt;strong&gt;A&lt;/strong&gt;vailability and &lt;strong&gt;C&lt;/strong&gt;onsistency; &lt;strong&gt;E&lt;/strong&gt;lse, even when everything is fine network-wise, we still must decide between low &lt;strong&gt;L&lt;/strong&gt;atency and &lt;strong&gt;C&lt;/strong&gt;onsistency.&lt;/p&gt;

&lt;p&gt;&lt;span class=&#34;markup-quote&#34;&gt;CRDTs are PA/EL&lt;/span&gt;. To achieve this, all updates are local to a replica. Then, in the background, replicas communicate in order to propagate new updates between them.&lt;/p&gt;

&lt;p&gt;This approach can lead to &lt;strong&gt;conflicts&lt;/strong&gt; when &lt;strong&gt;replicas concurrently write to the same object&lt;/strong&gt;. And if that happens, which write should win? Which write is the one we want?&lt;/p&gt;

&lt;h5 id=&#34;why-having-a-richer-abstraction-helps&#34;&gt;Why having a richer abstraction helps?&lt;/h5&gt;

&lt;p&gt;If we just have a &lt;strong&gt;register&lt;/strong&gt; abstraction, &lt;strong&gt;any two concurrent writes to the same object conflict&lt;/strong&gt;. But if these writes are increments to counters, there&amp;rsquo;s no conflict. Similarly, when elements are added to a set, no conflict is produced.&lt;/p&gt;

&lt;p&gt;The general rule is that &lt;em&gt;if two operations commute sequentially, then they are &lt;strong&gt;genuinely-conflict-free&lt;/strong&gt;&lt;/em&gt;.
When that doesn&amp;rsquo;t happen, CRDTs can pick one of the operations, becoming &lt;em&gt;&lt;strong&gt;artificially-conflict-free&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Examples of pairs of operations that are genuinely-CF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;increment / increment&lt;/li&gt;
&lt;li&gt;increment / decrement&lt;/li&gt;
&lt;li&gt;add A / add A&lt;/li&gt;
&lt;li&gt;add A / add B&lt;/li&gt;
&lt;li&gt;add A / remove B&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples of pairs of operations that &lt;strong&gt;can be&lt;/strong&gt; artificially-CF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write / write&lt;/li&gt;
&lt;li&gt;add A / remove A&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice the &amp;ldquo;can be&amp;rdquo;: once we have identified pairs of conflicting operations, we can pick one of these operations or not.
For example, a &lt;strong&gt;last-writer-wins register&lt;/strong&gt; will pick one of the writes (based on a wall-clock timestamp), but a &lt;strong&gt;multi-value register&lt;/strong&gt; will keep both (well, in fact, this is the only example I can think of in which both conflicting operations are kept).&lt;/p&gt;

&lt;h5 id=&#34;being-artificial-leads-to-concurrency-semantics&#34;&gt;Being artificial leads to concurrency semantics&lt;/h5&gt;

&lt;p&gt;Let&amp;rsquo;s focus on the last pair &lt;em&gt;add A / remove A&lt;/em&gt;. Here we have three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pick the add, and have a &lt;strong&gt;add-wins set&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;pick the remove, and have a &lt;strong&gt;remove-wins set&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;pick whichever has the highest timestamp, and have a &lt;strong&gt;last-writer-wins set&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For applications, now this means that they need to figure in which artificial way should potential conflicts be resolved.
For some, a removal can be discarded in the presence of an addition, while for others, the removal should always prevail.
(I was trying to come up with application examples for both, but all ideas felt too farfetched. Any suggestions?)&lt;/p&gt;

&lt;!-- (e.g. a shopping list being modified by two parents, one adds an item to be bought, the other removes it upon buying it). --&gt;

&lt;!-- (e.g. a shopping account being used by two users, one adds an item to the shopping cart, while another removes it). --&gt;

&lt;h4 id=&#34;before-we-go&#34;&gt;Before we go&lt;/h4&gt;

&lt;p&gt;If you&amp;rsquo;re curious on concurrency semantics for other data types, check Section 2.1 of this great CRDT overview by Nuno Preguiça: &lt;a href=&#34;https://arxiv.org/pdf/1806.10254.pdf&#34; target=&#34;_blank&#34;&gt;Conflict-free Replicated Data Types: An Overview&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And as a good-bye note, we can say that &amp;ldquo;only by being artificial, one can be completely conflict-free&amp;rdquo;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Efficient Synchronization of State-based CRDTs</title>
      <link>/publication/enes-efficient-synchronization/</link>
      <pubDate>Tue, 09 Apr 2019 00:00:00 +0100</pubDate>
      
      <guid>/publication/enes-efficient-synchronization/</guid>
      <description></description>
    </item>
    
    <item>
      <title>Threshold union: generalizing unions and intersections</title>
      <link>/post/2018/11/threshold-union/</link>
      <pubDate>Sun, 11 Nov 2018 23:04:00 +0000</pubDate>
      
      <guid>/post/2018/11/threshold-union/</guid>
      <description>

&lt;h3 id=&#34;part-i&#34;&gt;Part I&lt;/h3&gt;

&lt;p&gt;So, yesterday I was wondering about operations on a set of sets
(I&amp;rsquo;ll explain the Tweet content below, so you can just ignore it for now).&lt;/p&gt;

&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;when we have a set of sets S, an element belongs to the:&lt;br&gt;- union of S,           if it belongs to at least  1   sets in S&lt;br&gt;- intersection of S, if it belongs to at least  |S| sets in S&lt;br&gt;- _____ of S,           if it belongs to at least  N  sets in S&lt;br&gt;what should I write in _____?&lt;/p&gt;&amp;mdash; Vitor Enes (@vitorenesduarte) &lt;a href=&#34;https://twitter.com/vitorenesduarte/status/1061211944563212289?ref_src=twsrc%5Etfw&#34;&gt;November 10, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;



&lt;p&gt;For example, consider that we have 3 sets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$A = \{a, b, c\}$&lt;/li&gt;
&lt;li&gt;$B = \{a, b, d\}$&lt;/li&gt;
&lt;li&gt;$C = \{a\}$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and we build a set $S = \{A, B, C\}$ with the previous sets.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;union&lt;/strong&gt; of all sets has all elements:&lt;/p&gt;

&lt;p&gt;$$\bigcup S = \{a, b, c, d\}$$&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;intersection&lt;/strong&gt; of all sets has the elements common to all sets:&lt;/p&gt;

&lt;p&gt;$$\bigcap S = \{a\}$$&lt;/p&gt;

&lt;p&gt;Now, we can generalize these definitions and have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an element belongs to $\bigcup S$ if it belongs to at least 1 set in $S$&lt;/li&gt;
&lt;li&gt;an element belongs to $\bigcap S$ if it belongs to at least $|S|$ sets in $S$ &lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we have this, we can define $\bigcup_n$:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an element belongs to $\bigcup_n S$ if it belongs to at least $n$ sets in $S$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and $\bigcup$ and $\bigcap$ can be written in terms of $\bigcup_n$:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$\bigcup S = \bigcup_1 S$&lt;/li&gt;
&lt;li&gt;$\bigcap S = \bigcup_{|S|} S$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, my question was: &lt;strong&gt;&lt;em&gt;What&amp;rsquo;s the name of $\bigcup_n$&lt;/em&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After much googling and no success, it came to mind that maybe this was not about operations on sets, but instead on multisets:
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;Maybe this is about multisets. If we build a multiset with S, then the elements of _____ S are those with multiplicity bigger or equal to N. &lt;a href=&#34;https://t.co/qs58gi0Urs&#34;&gt;https://t.co/qs58gi0Urs&lt;/a&gt;&lt;/p&gt;&amp;mdash; Vitor Enes (@vitorenesduarte) &lt;a href=&#34;https://twitter.com/vitorenesduarte/status/1061222005100503041?ref_src=twsrc%5Etfw&#34;&gt;November 10, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;

&lt;/p&gt;

&lt;p&gt;Unlike a set, a &lt;strong&gt;multiset&lt;/strong&gt;, (and quoting &lt;a href=&#34;https://en.wikipedia.org/wiki/Multiset&#34; target=&#34;_blank&#34;&gt;Wikipedia&lt;/a&gt;) &amp;ldquo;&lt;em&gt;allows for multiple instances for each of its elements&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;In a multiset we keep count of the number of instances of each element - this number is called &lt;strong&gt;multiplicity&lt;/strong&gt;. I&amp;rsquo;ll use $e_m$ to represent an element $e$ with multiplicity $m$.&lt;/p&gt;

&lt;p&gt;So, with sets $A$, $B$ and $C$, we can build a multiset $\{a_3, b_2, c_1, d_1\}$.&lt;/p&gt;

&lt;p&gt;Using these concepts, we can redefine $\bigcup_n$:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an element belongs to $\bigcup_n S$ if its multiplicity in the multiset is at least $n$&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;part-ii&#34;&gt;Part II&lt;/h3&gt;

&lt;p&gt;Today, I was back on my quest.
This concept should be something classical, with like 100 years.
I was convinced that with this new insight (the multiset), I would finally find the name of $\bigcup_n$.&lt;/p&gt;

&lt;p&gt;What was I not expecting, was to find it in a recent (2005) multi-party computation (MPC) &lt;a href=&#34;https://www.cs.cmu.edu/~leak/papers/set-tech-full.pdf&#34; target=&#34;_blank&#34;&gt;paper&lt;/a&gt;. The paper is called &lt;strong&gt;Privacy-Preserving Set Operations&lt;/strong&gt; and is authored by Lea Kissner (&lt;a href=&#34;https://twitter.com/leakissner&#34; target=&#34;_blank&#34;&gt;@LeaKissner&lt;/a&gt;) and Dawn Song (&lt;a href=&#34;https://twitter.com/dawnsongtweets&#34; target=&#34;_blank&#34;&gt;@dawnsongtweets&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The high-level idea of MPC is to have a set of players computing some function on some inputs. The inputs are to be kept private, and only the function output should be revealed.&lt;/p&gt;

&lt;p&gt;So, if the inputs are the sets $A, B, C$ in $S$, and we&amp;rsquo;re computing their intersection, then only $\bigcap S = \{a\}$ should be known in the end.&lt;/p&gt;

&lt;p&gt;In Section 6.2, I found the following&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We define the &lt;strong&gt;Threshold Set-Union&lt;/strong&gt; problem as follows: all players learn
which elements appear in the combined private input of the players at least a threshold number $t$
times. For example, assume that $a$ appears in the combined private input of the players $15$ times.
If $t = 10$, then all players learn $a$. However, if $t = 16$, then no player learns $a$.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this, I declare my quest over, and I&amp;rsquo;ll be calling $\bigcup_n$ &lt;strong&gt;threshold union&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What do you think? Is there a better name? Has this concept been named elsewhere?&lt;/p&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;$|S|$ represents the size of the set. In the example, $|S| = 3$.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:1&#34;&gt;&lt;sup&gt;^&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;Although, there&amp;rsquo;s no mention of multiset in this definition, nor in the title, the paper contains several and I guess that&amp;rsquo;s why it came up in my Google search.
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:2&#34;&gt;&lt;sup&gt;^&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Detecting message stability with partial memberships</title>
      <link>/post/2018/10/stability/</link>
      <pubDate>Sat, 20 Oct 2018 12:35:00 +0100</pubDate>
      
      <guid>/post/2018/10/stability/</guid>
      <description>&lt;p&gt;


&lt;figure&gt;

&lt;img src=&#34;matrix.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Basic matrix-based technique.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;



&lt;figure&gt;

&lt;img src=&#34;opt.png&#34; /&gt;



&lt;figcaption data-pre=&#34;Figure &#34; data-post=&#34;:&#34; class=&#34;numbered&#34;&gt;
  &lt;h4&gt;Time-travel technique.&lt;/h4&gt;
  
&lt;/figcaption&gt;

&lt;/figure&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Borrowing an Identity for a Distributed Counter</title>
      <link>/talk/2018-05-22-borrow-counter/</link>
      <pubDate>Tue, 22 May 2018 00:00:00 +0100</pubDate>
      
      <guid>/talk/2018-05-22-borrow-counter/</guid>
      <description>
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube.com/embed/rGfbcu7UkGk&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;

</description>
    </item>
    
    <item>
      <title>Practical evaluation of the Lasp programming model at large scale: an experience report</title>
      <link>/publication/meiklejohn-lasp-eval/</link>
      <pubDate>Mon, 09 Oct 2017 00:00:00 +0100</pubDate>
      
      <guid>/publication/meiklejohn-lasp-eval/</guid>
      <description></description>
    </item>
    
    <item>
      <title>Efficient Synchronization of State-based CRDTs</title>
      <link>/publication/msc-thesis/</link>
      <pubDate>Tue, 03 Oct 2017 00:00:00 +0100</pubDate>
      
      <guid>/publication/msc-thesis/</guid>
      <description></description>
    </item>
    
    <item>
      <title>The Single-Writer Principle in CRDT Composition</title>
      <link>/publication/enes-single-writer-principle/</link>
      <pubDate>Tue, 20 Jun 2017 00:00:00 +0100</pubDate>
      
      <guid>/publication/enes-single-writer-principle/</guid>
      <description></description>
    </item>
    
    <item>
      <title>Borrowing an Identity for a Distributed Counter: Work in progress report</title>
      <link>/publication/enes-borrow-counter/</link>
      <pubDate>Sun, 23 Apr 2017 00:00:00 +0100</pubDate>
      
      <guid>/publication/enes-borrow-counter/</guid>
      <description></description>
    </item>
    
  </channel>
</rss>
