Files
nexus/sreweekly/articles/147/02-dbms-musings-distributed-consistency-at-scale-spanner-vs-calvin.html
2026-09-12 17:23:01 +08:00

1957 lines
95 KiB
HTML

<!DOCTYPE html>
<html class='v2' dir='ltr' lang='en'>
<head>
<link href='https://www.blogger.com/static/v1/widgets/2872013778-css_bundle_v2.css' rel='stylesheet' type='text/css'/>
<meta content='width=1100' name='viewport'/>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
<meta content='blogger' name='generator'/>
<link href='http://dbmsmusings.blogspot.com/favicon.ico' rel='icon' type='image/x-icon'/>
<link href='http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html' rel='canonical'/>
<link rel="alternate" type="application/atom+xml" title="DBMS Musings - Atom" href="http://dbmsmusings.blogspot.com/feeds/posts/default" />
<link rel="alternate" type="application/rss+xml" title="DBMS Musings - RSS" href="http://dbmsmusings.blogspot.com/feeds/posts/default?alt=rss" />
<link rel="service.post" type="application/atom+xml" title="DBMS Musings - Atom" href="https://draft.blogger.com/feeds/8899645800948009496/posts/default" />
<link rel="alternate" type="application/atom+xml" title="DBMS Musings - Atom" href="http://dbmsmusings.blogspot.com/feeds/6145769827958755916/comments/default" />
<!--Can't find substitution for tag [blog.ieCssRetrofitLinks]-->
<meta content='http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html' property='og:url'/>
<meta content='Distributed consistency at scale: Spanner vs. Calvin' property='og:title'/>
<meta content=' Introduction In 2012, two research papers were published that described the design of geographically replicated, consistent, ACID complia...' property='og:description'/>
<title>DBMS Musings: Distributed consistency at scale: Spanner vs. Calvin</title>
<style id='page-skin-1' type='text/css'><!--
/*
-----------------------------------------------
Blogger Template Style
Name: Ethereal
Designer: Jason Morrow
URL: jasonmorrow.etsy.com
----------------------------------------------- */
/* Content
----------------------------------------------- */
body {
font: normal normal 13px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
background: #fb5e53 url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/birds-2toned-bg.png) repeat-x scroll top center;
}
html body .content-outer {
min-width: 0;
max-width: 100%;
width: 100%;
}
a:link {
text-decoration: none;
color: #2198a6;
}
a:visited {
text-decoration: none;
color: #4d469c;
}
a:hover {
text-decoration: underline;
color: #2198a6;
}
.main-inner {
padding-top: 15px;
}
.body-fauxcolumn-outer {
background: transparent none repeat-x scroll top center;
}
.content-fauxcolumns .fauxcolumn-inner {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
border-left: 1px solid #fb5e53;
border-right: 1px solid #fb5e53;
}
/* Flexible Background
----------------------------------------------- */
.content-fauxcolumn-outer .fauxborder-left {
width: 100%;
padding-left: 300px;
margin-left: -300px;
background-color: transparent;
background-image: url(//themes.googleusercontent.com/image?id=0BwVBOzw_-hbMNjViMzQ0ZDEtMWU1NS00ZTBkLWFjY2EtZjM5YmU4OTA2MjBm);
background-repeat: no-repeat;
background-position: left top;
}
.content-fauxcolumn-outer .fauxborder-right {
margin-right: -299px;
width: 299px;
background-color: transparent;
background-image: url(//themes.googleusercontent.com/image?id=0BwVBOzw_-hbMNjViMzQ0ZDEtMWU1NS00ZTBkLWFjY2EtZjM5YmU4OTA2MjBm);
background-repeat: no-repeat;
background-position: right top;
}
/* Columns
----------------------------------------------- */
.content-inner {
padding: 0;
}
/* Header
----------------------------------------------- */
.header-inner {
padding: 27px 0 3px;
}
.header-inner .section {
margin: 0 35px;
}
.Header h1 {
font: normal normal 60px Times, 'Times New Roman', FreeSerif, serif;
color: #ff8b8b;
}
.Header h1 a {
color: #ff8b8b;
}
.Header .description {
font-size: 115%;
color: #666666;
}
.header-inner .Header .titlewrapper,
.header-inner .Header .descriptionwrapper {
padding-left: 0;
padding-right: 0;
margin-bottom: 0;
}
/* Tabs
----------------------------------------------- */
.tabs-outer {
position: relative;
background: transparent;
}
.tabs-cap-top, .tabs-cap-bottom {
position: absolute;
width: 100%;
}
.tabs-cap-bottom {
bottom: 0;
}
.tabs-inner {
padding: 0;
}
.tabs-inner .section {
margin: 0 35px;
}
*+html body .tabs-inner .widget li {
padding: 1px;
}
.PageList {
border-bottom: 1px solid #fb5e53;
}
.tabs-inner .widget li.selected a,
.tabs-inner .widget li a:hover {
position: relative;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-goog-ms-border-top-left-radius: 5px;
-goog-ms-border-top-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
background: #ffa183 none ;
color: #ffffff;
}
.tabs-inner .widget li a {
display: inline-block;
margin: 0;
margin-right: 1px;
padding: .65em 1.5em;
font: normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
background-color: #ffdfc7;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-goog-ms-border-top-left-radius: 5px;
-goog-ms-border-top-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
/* Headings
----------------------------------------------- */
h2 {
font: normal bold 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
color: #666666;
}
/* Widgets
----------------------------------------------- */
.main-inner .column-left-inner {
padding: 0 0 0 20px;
}
.main-inner .column-left-inner .section {
margin-right: 0;
}
.main-inner .column-right-inner {
padding: 0 20px 0 0;
}
.main-inner .column-right-inner .section {
margin-left: 0;
}
.main-inner .section {
padding: 0;
}
.main-inner .widget {
padding: 0 0 15px;
margin: 20px 0;
border-bottom: 1px solid #dbdbdb;
}
.main-inner .widget h2 {
margin: 0;
padding: .6em 0 .5em;
}
.footer-inner .widget h2 {
padding: 0 0 .4em;
}
.main-inner .widget h2 + div, .footer-inner .widget h2 + div {
padding-top: 15px;
}
.main-inner .widget .widget-content {
margin: 0;
padding: 15px 0 0;
}
.main-inner .widget ul, .main-inner .widget #ArchiveList ul.flat {
margin: -15px -15px -15px;
padding: 0;
list-style: none;
}
.main-inner .sidebar .widget h2 {
border-bottom: 1px solid #dbdbdb;
}
.main-inner .widget #ArchiveList {
margin: -15px 0 0;
}
.main-inner .widget ul li, .main-inner .widget #ArchiveList ul.flat li {
padding: .5em 15px;
text-indent: 0;
}
.main-inner .widget #ArchiveList ul li {
padding-top: .25em;
padding-bottom: .25em;
}
.main-inner .widget ul li:first-child, .main-inner .widget #ArchiveList ul.flat li:first-child {
border-top: none;
}
.main-inner .widget ul li:last-child, .main-inner .widget #ArchiveList ul.flat li:last-child {
border-bottom: none;
}
.main-inner .widget .post-body ul {
padding: 0 2.5em;
margin: .5em 0;
list-style: disc;
}
.main-inner .widget .post-body ul li {
padding: 0.25em 0;
margin-bottom: .25em;
color: #666666;
border: none;
}
.footer-inner .widget ul {
padding: 0;
list-style: none;
}
.widget .zippy {
color: #cccccc;
}
/* Posts
----------------------------------------------- */
.main.section {
margin: 0 20px;
}
body .main-inner .Blog {
padding: 0;
background-color: transparent;
border: none;
}
.main-inner .widget h2.date-header {
border-bottom: 1px solid #dbdbdb;
}
.date-outer {
position: relative;
margin: 15px 0 20px;
}
.date-outer:first-child {
margin-top: 0;
}
.date-posts {
clear: both;
}
.post-outer, .inline-ad {
border-bottom: 1px solid #dbdbdb;
padding: 30px 0;
}
.post-outer {
padding-bottom: 10px;
}
.post-outer:first-child {
padding-top: 0;
border-top: none;
}
.post-outer:last-child, .inline-ad:last-child {
border-bottom: none;
}
.post-body img {
padding: 8px;
}
h3.post-title, h4 {
font: normal normal 24px Times, Times New Roman, serif;
color: #2198a6;
}
h3.post-title a {
font: normal normal 24px Times, Times New Roman, serif;
color: #2198a6;
text-decoration: none;
}
h3.post-title a:hover {
color: #2198a6;
text-decoration: underline;
}
.post-header {
margin: 0 0 1.5em;
}
.post-body {
line-height: 1.4;
}
.post-footer {
margin: 1.5em 0 0;
}
#blog-pager {
padding: 15px;
}
.blog-feeds, .post-feeds {
margin: 1em 0;
text-align: center;
}
.post-outer .comments {
margin-top: 2em;
}
/* Comments
----------------------------------------------- */
.comments .comments-content .icon.blog-author {
background-repeat: no-repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==);
}
.comments .comments-content .loadmore a {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
}
.comments .comments-content .loadmore a {
border-top: 1px solid #dbdbdb;
border-bottom: 1px solid #dbdbdb;
}
.comments .comment-thread.inline-thread {
background: #ffffff url(https://resources.blogblog.com/blogblog/data/1kt/ethereal/bird-2toned-blue-fade.png) repeat-x scroll top left;
}
.comments .continue {
border-top: 2px solid #dbdbdb;
}
/* Footer
----------------------------------------------- */
.footer-inner {
padding: 30px 0;
overflow: hidden;
}
/* Mobile
----------------------------------------------- */
body.mobile {
background-size: auto
}
.mobile .body-fauxcolumn-outer {
background: ;
}
.mobile .content-fauxcolumns .fauxcolumn-inner {
opacity: 0.75;
}
.mobile .content-fauxcolumn-outer .fauxborder-right {
margin-right: 0;
}
.mobile-link-button {
background-color: #ffa183;
}
.mobile-link-button a:link, .mobile-link-button a:visited {
color: #ffffff;
}
.mobile-index-contents {
color: #444444;
}
.mobile .body-fauxcolumn-outer {
background-size: 100% auto;
}
.mobile .mobile-date-outer {
border-bottom: transparent;
}
.mobile .PageList {
border-bottom: none;
}
.mobile .tabs-inner .section {
margin: 0;
}
.mobile .tabs-inner .PageList .widget-content {
background: #ffa183 none;
color: #ffffff;
}
.mobile .tabs-inner .PageList .widget-content .pagelist-arrow {
border-left: 1px solid #ffffff;
}
.mobile .footer-inner {
overflow: visible;
}
body.mobile .AdSense {
margin: 0 -10px;
}
--></style>
<style id='template-skin-1' type='text/css'><!--
body {
min-width: 1310px;
}
.content-outer, .content-fauxcolumn-outer, .region-inner {
min-width: 1310px;
max-width: 1310px;
_width: 1310px;
}
.main-inner .columns {
padding-left: 0;
padding-right: 350px;
}
.main-inner .fauxcolumn-center-outer {
left: 0;
right: 350px;
/* IE6 does not respect left and right together */
_width: expression(this.parentNode.offsetWidth -
parseInt("0") -
parseInt("350px") + 'px');
}
.main-inner .fauxcolumn-left-outer {
width: 0;
}
.main-inner .fauxcolumn-right-outer {
width: 350px;
}
.main-inner .column-left-outer {
width: 0;
right: 100%;
margin-left: -0;
}
.main-inner .column-right-outer {
width: 350px;
margin-right: -350px;
}
#layout {
min-width: 0;
}
#layout .content-outer {
min-width: 0;
width: 800px;
}
#layout .region-inner {
min-width: 0;
width: auto;
}
body#layout div.add_widget {
padding: 8px;
}
body#layout div.add_widget a {
margin-left: 32px;
}
--></style>
<!-- Google tag (gtag.js) -->
<script async='true' src='https://www.googletagmanager.com/gtag/js?id=G-WPSPKTZ8VQ'></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-WPSPKTZ8VQ');
</script>
<link href='https://draft.blogger.com/dyncss/8899645800948009496/authorization.css?zx=64628a2a-8581-41e2-b103-b6627e610902' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://draft.blogger.com/dyncss/8899645800948009496/authorization.css?zx=64628a2a-8581-41e2-b103-b6627e610902' rel='stylesheet'/></noscript>
<meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/>
<meta name='google-adsense-platform-domain' content='blogspot.com'/>
</head>
<body class='loading variant-hummingBirds2'>
<div class='navbar section' id='navbar' name='Navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript">
function setAttributeOnload(object, attribute, val) {
if(window.addEventListener) {
window.addEventListener('load',
function(){ object[attribute] = val; }, false);
} else {
window.attachEvent('onload', function(){ object[attribute] = val; });
}
}
</script>
<div id="navbar-iframe-container"></div>
<script type="text/javascript" src="https://apis.google.com/js/platform.js"></script>
<script type="text/javascript">
gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() {
if (gapi.iframes && gapi.iframes.getContext) {
gapi.iframes.getContext().openChild({
url: 'https://draft.blogger.com/navbar/8899645800948009496?po\x3d6145769827958755916\x26origin\x3dhttp://dbmsmusings.blogspot.com',
where: document.getElementById("navbar-iframe-container"),
id: "navbar-iframe"
});
}
});
</script><script type="text/javascript">
(function() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js';
var head = document.getElementsByTagName('head')[0];
if (head) {
head.appendChild(script);
}})();
</script>
</div></div>
<div class='body-fauxcolumns'>
<div class='fauxcolumn-outer body-fauxcolumn-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<div class='content'>
<div class='content-fauxcolumns'>
<div class='fauxcolumn-outer content-fauxcolumn-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<div class='content-outer'>
<div class='content-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left content-fauxborder-left'>
<div class='fauxborder-right content-fauxborder-right'></div>
<div class='content-inner'>
<header>
<div class='header-outer'>
<div class='header-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left header-fauxborder-left'>
<div class='fauxborder-right header-fauxborder-right'></div>
<div class='region-inner header-inner'>
<div class='header section' id='header' name='Header'><div class='widget Header' data-version='1' id='Header1'>
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
<a href='http://dbmsmusings.blogspot.com/'>
DBMS Musings
</a>
</h1>
</div>
<div class='descriptionwrapper'>
<p class='description'><span>
</span></p>
</div>
</div>
</div></div>
</div>
</div>
<div class='header-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</header>
<div class='tabs-outer'>
<div class='tabs-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left tabs-fauxborder-left'>
<div class='fauxborder-right tabs-fauxborder-right'></div>
<div class='region-inner tabs-inner'>
<div class='tabs no-items section' id='crosscol' name='Cross-Column'></div>
<div class='tabs no-items section' id='crosscol-overflow' name='Cross-Column 2'></div>
</div>
</div>
<div class='tabs-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='main-outer'>
<div class='main-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left main-fauxborder-left'>
<div class='fauxborder-right main-fauxborder-right'></div>
<div class='region-inner main-inner'>
<div class='columns fauxcolumns'>
<div class='fauxcolumn-outer fauxcolumn-center-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='fauxcolumn-outer fauxcolumn-left-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<div class='fauxcolumn-outer fauxcolumn-right-outer'>
<div class='cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left'>
<div class='fauxborder-right'></div>
<div class='fauxcolumn-inner'>
</div>
</div>
<div class='cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<!-- corrects IE6 width calculation -->
<div class='columns-inner'>
<div class='column-center-outer'>
<div class='column-center-inner'>
<div class='main section' id='main' name='Main'><div class='widget Blog' data-version='1' id='Blog1'>
<div class='blog-posts hfeed'>
<div class="date-outer">
<h2 class='date-header'><span>Thursday, April 6, 2017</span></h2>
<div class="date-posts">
<div class='post-outer'>
<div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'>
<meta content='8899645800948009496' itemprop='blogId'/>
<meta content='6145769827958755916' itemprop='postId'/>
<a name='6145769827958755916'></a>
<h3 class='post-title entry-title' itemprop='name'>
Distributed consistency at scale: Spanner vs. Calvin
</h3>
<div class='post-header'>
<div class='post-header-line-1'></div>
</div>
<div class='post-body entry-content' id='post-body-6145769827958755916' itemprop='description articleBody'>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
Introduction</h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In 2012, two research papers were published that described the design of geographically replicated, consistent, ACID compliant, transactional database systems. Both papers criticized the proliferation of NoSQL database systems that compromise replication consistency and transactional support, and argue that it is very possible to build extremely scalable, geographically replicated systems without giving up on consistency and transactional support. The first of these papers was the </span><a href="http://cs-www.cs.yale.edu/homes/dna/papers/calvin-sigmod12.pdf" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Calvin paper</span></a><span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, published in SIGMOD 2012. A few months later, Google published their </span><a href="https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Spanner paper</span></a><span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in OSDI 2012. Both of these papers have been cited many hundreds of times and have influenced the design of several modern &#8220;NewSQL&#8221; systems, including </span><span style="background-color: transparent; color: #1155cc; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"><a href="https://fauna.com/" style="text-decoration: none;">FaunaDB</a></span><span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (where this post is also being published).
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Recently, Google released a beta version of their Spanner implementation, available to customers who use Google Cloud Platform. This development has excited many users seeking to build scalable apps on Google&#8217;s cloud, since they now have a reliably scalable and consistent transactional database system to use as a foundation. However, the availability of Spanner outside of Google has also brought it more scrutiny --- what are its technical advantages in practice, and what are its costs? Even though it has been five years since the Calvin paper was published, it is only now that the database community is asking me to directly compare and contrast the technical designs of Calvin and Spanner.
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The goal of this post is to do exactly that --- compare the architectural design decisions made in these two systems, and specifically focus on the advantages and disadvantages of these decisions against each other as they relate to performance and scalability. This post is focused on the protocols described in the original papers from 2012. Although the publicly available versions of these systems likely have deviated from the original papers, the core architectural distinctions remain the same.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The CAP theorem in context</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Before we get started, allow me to suggest the following: Ignore the CAP theorem in the context of this discussion. Just forget about it. It&#8217;s not relevant for the type of modern architectural deployments discussed in this post where network partitions are rare.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Both Spanner and Calvin replicate data across independent regions for high availability. And both Spanner and Calvin are technically CP systems from CAP: they guarantee 100% consistency (serializability, linearizability, etc.) across the entire system. Yes, when there is a network partition, both systems make slight compromises on availability, but partitions are rare enough in practice that developers on top of both systems can assume a fully-available system to many 9s of availability.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(BTW: </span><span style="font-family: &quot;arial&quot;; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">If you didn&#8217;t believe me in 2010 when I <a href="http://dbmsmusings.blogspot.co.il/2010/04/problems-with-cap-and-yahoos-little.html" target="_blank">explained the shortfalls of using CAP to understand the practical consistency and availability properties of modern systems</a></span><span style="font-family: &quot;arial&quot;; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">, maybe you will believe the author of the CAP theorem himself, Eric Brewer, who <a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45855.pdf" target="_blank">recommends against analyzing Spanner through the lens of the CAP theorem</a>.)</span><a href="https://static.googleusercontent.com/media/research.google.com/en/pubs/archive/45855.pdf" style="text-decoration: none;"><span style="color: black; font-family: &quot;arial&quot;; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"> </span></a></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ordering transactions in time</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let us start our comparison of Calvin and Spanner with the most obvious difference between them: Spanner&#8217;s use of &#8220;TrueTime&#8221; vs. Calvin&#8217;s use of &#8220;preprocessing&#8221; (or &#8220;sequencing&#8221; in the language of the original paper) for transaction ordering. In fact, most of the other differences between Spanner and Calvin stem from this fundamental choice.
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A serializable system provides a notion of transactional ordering. Even though many transactions may be executed in parallel across many CPUs and many servers in a large distributed system, the final state (and all observable intermediate states) must be as if each transaction was processed one-by-one. If no transactions touch the same data, it is trivial to process them in parallel and maintain this guarantee. However, if the transactions read or write each other&#8217;s data, then they must be ordered against each other, with one considered earlier than the other. The one considered &#8220;later&#8221; must be processed against a version of the database state that includes the writes of the earlier one. In addition, the one considered &#8220;earlier&#8221; must be processed against a version of the database state that excludes the writes of the later one.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Locking and logging</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spanner uses TrueTime for this transaction ordering. Google famously uses a combination of GPS and atomic clocks in all of their regions to synchronize time to within a known uncertainty bound. If two transactions are processed during time periods that do not have overlapping uncertainty bounds, Spanner can be certain that the later transaction will see all the writes of the earlier transaction.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spanner obtains write locks within the data replicas on all the data it will write before performing any write. If it obtains all the locks it needs, it proceeds with all of its writes and then assigns the transaction a timestamp at the end of the uncertainty range of the coordinator server for that transaction. It then waits until this later timestamp has definitely passed for all servers in the system (which is the entire length of the uncertainty range) and then releases locks and commits the transaction. Future transactions will get later timestamps and see all the writes of this earlier transaction. Thus, in Spanner, every transaction receives a timestamp based on the actual time that it committed, and this timestamp is used to order transactions. Transactions with later timestamps see all the writes of transactions with earlier timestamps, with locking used to enforce this guarantee.
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In contrast, Calvin uses preprocessing to order transactions. All transactions are inserted into a distributed, replicated log before being processed. In more detail: clients submit transactions to the preprocessing layer of their local region, which then submits these transactions to the global log via a cross-region consensus process like Paxos. This is similar to a write-ahead log in a traditional, non-distributed database. The order that the transactions appear in this log is the official transaction ordering. Every replica reads from their local copy of this replicated log and processes transactions in a way that guarantees that their final state is equivalent to what it would have been had every transaction in the log been executed one-by-one.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Replication overhead</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The design difference between TrueTime vs. preprocessing directly leads to a difference in how the systems perform replication. In Cavlin, the replication of transactional input during preprocessing is the only replication that is needed. Calvin uses a deterministic execution framework to avoid *all* cross-replication communication during normal (non-recovery mode) execution aside from preprocessing. Every replica sees the same log of transactions and guarantees not only a final state equivalent to executing the transactions in this log one-by-one, but also a final state equivalent to every other replica.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This requires the preprocessor to analyze the transaction code and &#8220;pre-execute&#8221; any nondeterministic code (e.g. calls to sys.random() or time.now()). (The implication of this in terms of what types of transactions are supported by Calvin are discussed at the end of this post.) Once all code within a transaction is deterministic, a replica can safely focus on just processing the transactions in the log in the correct order without concern for diverging with the other replicas. &nbsp;
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In contrast, since Spanner does not do any transaction preprocessing, it can only perform replication after transaction execution. Spanner performs this replication via a cross-region Paxos process.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The cost of two-phase commit</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Another key difference between Spanner and Calvin is how they commit multi-partitioned transactions. Both Calvin and Spanner partition data into separate shards that may be stored on separate machines that fail independently from each other. In order to guarantee transaction atomicity and durability, any transaction that accesses data in multiple partitions must go through a commit procedure that ensures that every partition successfully processed the part of the transaction that accessed data in that partition. Since machines may fail at any time, including during the commit procedure, this process generally takes two rounds of communication between the partitions involved in the transaction. This two-round commit protocol is called &#8220;two phase commit&#8221; and is used in almost every ACID-compliant distributed database system, including Spanner. This two phase commit protocol can often consume the majority of latency for short, simple transactions since the actual processing time of the transaction is much less than the delays involved in sending and receiving two rounds of messages over the network.
</span><span style="font-family: &quot;arial&quot;; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The cost of two phase commit is particularly high in Spanner because the protocol involves three forced writes to a log that cannot be overlapped with each other. In Spanner, every force write to a log involves a cross-region Paxos agreement, so the latency of two phase commit in Spanner is at least equal to three times the latency of cross-region Paxos.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Determinism is durability</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In contrast to Spanner, Calvin leverages deterministic execution to avoid two-phase commit. Machine failures do not cause transactional aborts in Calvin. Instead, after a failure, the machine that failed in Calvin re-reads the input transaction log from a checkpoint, and deterministically replays it to recover its state at the time of the failure. It can then continue on from there as if nothing happened. As a result, the commit protocol does not need to worry about machine failures during the protocol, and can be performed in a single round of communication (and in some cases, zero rounds of communication --- see the original paper for more details).</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Performance</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At this point, I think I have provided enough details to make it possible to present a theoretical comparison of the bottom line performance of Calvin vs. Spanner for a variety of different types of requests. &nbsp;This comparison assumes a perfectly optimized and implemented version of each system.</span></div>
<h4 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 14pt;">
<span style="background-color: transparent; color: #666666; font-family: &quot;arial&quot;; font-size: 12pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Transactional write latency</span></h4>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A transaction that is &#8220;non-read-only&#8221; writes at least one value to the database state. In Calvin, such a transaction must pay the latency cost of preprocessing, which is roughly the cost of running cross-region Paxos to agree to append the transaction to the log. After this is complete, the remaining latency is the cost of processing the transaction itself, which includes the zero or one-phase commit protocol for distributed transactions.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In Spanner, there is no preprocessing latency, but it still has to pay the cost of cross-region Paxos replication at commit time, which is roughly equivalent to the Calvin preprocessing latency. Spanner also has to pay the commit wait latency discussed above (which is the size of the time uncertainty window), but this can be overlapped with replication. It also pays the latency of two phase commit for multi-partition transactions.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thus, Spanner and Calvin have roughly equivalent latency for single-partition transactions, but Spanner has worse latency than Calvin for multi-partition transactions due to the extra phases in the transaction commit protocol.</span></div>
<h4 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 14pt;">
<span style="background-color: transparent; color: #666666; font-family: &quot;arial&quot;; font-size: 12pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
Snapshot read latency</span></h4>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Both Calvin and Spanner keep around older versions of data and read data at a requested earlier timestamp from a local replica without any Paxos-communication with the other replicas.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thus, both Calvin and Spanner can achieve very low snapshot-read latency.</span></div>
<h4 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 14pt;">
<span style="background-color: transparent; color: #666666; font-family: &quot;arial&quot;; font-size: 12pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
Transactional read latency</span></h4>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read-only transactions do not write any data, but they must be linearizable with respect to other transactions that write data. In practice, Calvin accomplishes this via placing the read-only transaction in the preprocessor log. This means that a read-only transaction in Calvin must pay the cross-region replication latency. In contrast, Spanner only needs to submit the read-only transaction to the leader replica(s) for the partition(s) that are accessed in order to get a global timestamp (and therefore be ordered relative to concurrent transactions). Therefore, there is no cross-region Paxos latency --- only the commit time (uncertainty window) latency.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thus, Spanner has better latency than Calvin for read-only transactions submitted by clients that are physically close to the location of the leader servers for the partitions accessed by that transaction.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
Scalability</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Both Spanner and Calvin are both (theoretically) roughly-linearly scalable for transactional workloads for which it is rare for concurrent transactions to be accessing the same data. However, major differences begin to present themselves as the conflict rate between concurrent transactions starts to increase.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Both Spanner and Calvin, as presented in the paper, use locks to prevent concurrent transactions from interfering with each other in impermissible ways. However, the amount of time they hold locks for an identical transaction is substantially different. Both systems need to hold locks during the commit protocol. However, since Calvin&#8217;s commit protocol is shorter than Spanner&#8217;s, Calvin reduces the lock hold time at the end of the transaction. On the flip side, Calvin acquires all locks that it will need at the beginning of the transaction, whereas Spanner performs all reads for a transaction before acquiring write locks. Therefore, Spanner reduces lock time at the beginning of the transaction.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, this latter advantage for Spanner is generally outweighed by the former (extra lock-hold time at the end of the transactions) disadvantage, since, as discussed above, the latency of two-phase commit in Spanner involves at least three iterations of cross-region Paxos. Furthermore, Spanner has an additional major disadvantage relative to Calvin in lock-hold time: Spanner must also hold locks during replication (which, as mentioned above, is also a cross-region Paxos process). The farther apart the regions, the larger the latency of this replication, and therefore, the longer Spanner must hold locks.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In contrast, Calvin does its replication during preprocessing, and therefore does not need to hold locks during replication. This leads to Calvin holding locks for much shorter periods of time than Spanner, and therefore being able to process more concurrent transactions in parallel that conflict with each other.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A second difference that can affect scalability is the following: Calvin requires only a single Paxos group for replicating the input log. In contrast, Spanner requires one independent Paxos group per shard, with proportionally higher overhead.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overall, Calvin has higher throughput scalability than Spanner for transactional workloads where concurrent transactions access the same data. This advantage increases with the distance between datacenters.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
Limitations</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to implement deterministic transaction processing, Calvin requires the preprocessor to analyze transactions and potentially &#8220;pre-execute&#8221; any non-deterministic code to ensure that replicas do not diverge. This implies that the preprocessor requires the entire transaction to be submitted at once. This highlights another difference between Calvin and Spanner --- while Spanner theoretically allows arbitrary client-side interactive transactions (that may include external communication), Calvin supports a more limited transaction model.
</span><span style="font-family: arial; font-size: 11pt; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are some subtle, but interesting differences between Calvin and Spanner in rare situations where every single replica for a shard is unavailable, or if all but one are unavailable, but these differences are out of scope for this post.</span></div>
<h3 dir="ltr" style="line-height: 1.38; margin-bottom: 4pt; margin-top: 16pt;">
<span style="background-color: transparent; color: #434343; font-family: &quot;arial&quot;; font-size: 14pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">
Conclusion</span></h3>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">I&#8217;m obviously biased in favor of Calvin, but in going through this exercise, I found it very difficult to find cases where an ideal implementation of Spanner theoretically outperforms an ideal implementation of Calvin. The only place where I could find that Spanner has a clear performance advantage over Calvin is for latency of read-only transactions submitted by clients that are physically close to the location of the leader servers for the partitions accessed by that transaction. Since any complex transaction is likely to touch multiple partitions, this is almost impossible to guarantee in a real-world setting.
</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, many real-world workloads do not require client-side interactive transactions, and furthermore only need transactional support for writes and are satisfied with performing reads against a snapshots (after all, this is the default isolation model of many SQL systems). It seems to me that Calvin is the better fit for a large class of modern applications.</span></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span></div>
<div>
<span style="background-color: transparent; color: black; font-family: &quot;arial&quot;; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div style='clear: both;'></div>
</div>
<div class='post-footer'>
<div class='post-footer-line post-footer-line-1'>
<span class='post-author vcard'>
Posted by
<span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'>
<meta content='https://draft.blogger.com/profile/16753133043157018521' itemprop='url'/>
<a class='g-profile' href='https://draft.blogger.com/profile/16753133043157018521' rel='author' title='author profile'>
<span itemprop='name'>Daniel Abadi</span>
</a>
</span>
</span>
<span class='post-timestamp'>
at
<meta content='http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html' itemprop='url'/>
<a class='timestamp-link' href='http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2017-04-06T10:59:00-07:00'>10:59&#8239;AM</abbr></a>
</span>
<span class='post-comment-link'>
</span>
<span class='post-icons'>
<span class='item-control blog-admin pid-2045359914'>
<a href='https://draft.blogger.com/post-edit.g?blogID=8899645800948009496&postID=6145769827958755916&from=pencil' title='Edit Post'>
<img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/>
</a>
</span>
</span>
<div class='post-share-buttons goog-inline-block'>
<a class='goog-inline-block share-button sb-email' href='https://draft.blogger.com/share-post.g?blogID=8899645800948009496&postID=6145769827958755916&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://draft.blogger.com/share-post.g?blogID=8899645800948009496&postID=6145769827958755916&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://draft.blogger.com/share-post.g?blogID=8899645800948009496&postID=6145769827958755916&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://draft.blogger.com/share-post.g?blogID=8899645800948009496&postID=6145769827958755916&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://draft.blogger.com/share-post.g?blogID=8899645800948009496&postID=6145769827958755916&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a>
</div>
</div>
<div class='post-footer-line post-footer-line-2'>
<span class='post-labels'>
</span>
</div>
<div class='post-footer-line post-footer-line-3'>
<span class='post-location'>
</span>
</div>
</div>
</div>
<div class='comments' id='comments'>
<a name='comments'></a>
<h4>1 comment:</h4>
<div class='comments-content'>
<script async='async' src='' type='text/javascript'></script>
<script type='text/javascript'>
(function() {
var items = null;
var msgs = null;
var config = {};
// <![CDATA[
var cursor = null;
if (items && items.length > 0) {
cursor = parseInt(items[items.length - 1].timestamp) + 1;
}
var bodyFromEntry = function(entry) {
var text = (entry &&
((entry.content && entry.content.$t) ||
(entry.summary && entry.summary.$t))) ||
'';
if (entry && entry.gd$extendedProperty) {
for (var k in entry.gd$extendedProperty) {
if (entry.gd$extendedProperty[k].name == 'blogger.contentRemoved') {
return '<span class="deleted-comment">' + text + '</span>';
}
}
}
return text;
}
var parse = function(data) {
cursor = null;
var comments = [];
if (data && data.feed && data.feed.entry) {
for (var i = 0, entry; entry = data.feed.entry[i]; i++) {
var comment = {};
// comment ID, parsed out of the original id format
var id = /blog-(\d+).post-(\d+)/.exec(entry.id.$t);
comment.id = id ? id[2] : null;
comment.body = bodyFromEntry(entry);
comment.timestamp = Date.parse(entry.published.$t) + '';
if (entry.author && entry.author.constructor === Array) {
var auth = entry.author[0];
if (auth) {
comment.author = {
name: (auth.name ? auth.name.$t : undefined),
profileUrl: (auth.uri ? auth.uri.$t : undefined),
avatarUrl: (auth.gd$image ? auth.gd$image.src : undefined)
};
}
}
if (entry.link) {
if (entry.link[2]) {
comment.link = comment.permalink = entry.link[2].href;
}
if (entry.link[3]) {
var pid = /.*comments\/default\/(\d+)\?.*/.exec(entry.link[3].href);
if (pid && pid[1]) {
comment.parentId = pid[1];
}
}
}
comment.deleteclass = 'item-control blog-admin';
if (entry.gd$extendedProperty) {
for (var k in entry.gd$extendedProperty) {
if (entry.gd$extendedProperty[k].name == 'blogger.itemClass') {
comment.deleteclass += ' ' + entry.gd$extendedProperty[k].value;
} else if (entry.gd$extendedProperty[k].name == 'blogger.displayTime') {
comment.displayTime = entry.gd$extendedProperty[k].value;
}
}
}
comments.push(comment);
}
}
return comments;
};
var paginator = function(callback) {
if (hasMore()) {
var url = config.feed + '?alt=json&v=2&orderby=published&reverse=false&max-results=50';
if (cursor) {
url += '&published-min=' + new Date(cursor).toISOString();
}
window.bloggercomments = function(data) {
var parsed = parse(data);
cursor = parsed.length < 50 ? null
: parseInt(parsed[parsed.length - 1].timestamp) + 1
callback(parsed);
window.bloggercomments = null;
}
url += '&callback=bloggercomments';
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
};
var hasMore = function() {
return !!cursor;
};
var getMeta = function(key, comment) {
if ('iswriter' == key) {
var matches = !!comment.author
&& comment.author.name == config.authorName
&& comment.author.profileUrl == config.authorUrl;
return matches ? 'true' : '';
} else if ('deletelink' == key) {
return config.baseUri + '/comment/delete/'
+ config.blogId + '/' + comment.id;
} else if ('deleteclass' == key) {
return comment.deleteclass;
}
return '';
};
var replybox = null;
var replyUrlParts = null;
var replyParent = undefined;
var onReply = function(commentId, domId) {
if (replybox == null) {
// lazily cache replybox, and adjust to suit this style:
replybox = document.getElementById('comment-editor');
if (replybox != null) {
replybox.height = '250px';
replybox.style.display = 'block';
replyUrlParts = replybox.src.split('#');
}
}
if (replybox && (commentId !== replyParent)) {
replybox.src = '';
document.getElementById(domId).insertBefore(replybox, null);
replybox.src = replyUrlParts[0]
+ (commentId ? '&parentID=' + commentId : '')
+ '#' + replyUrlParts[1];
replyParent = commentId;
}
};
var hash = (window.location.hash || '#').substring(1);
var startThread, targetComment;
if (/^comment-form_/.test(hash)) {
startThread = hash.substring('comment-form_'.length);
} else if (/^c[0-9]+$/.test(hash)) {
targetComment = hash.substring(1);
}
// Configure commenting API:
var configJso = {
'maxDepth': config.maxThreadDepth
};
var provider = {
'id': config.postId,
'data': items,
'loadNext': paginator,
'hasMore': hasMore,
'getMeta': getMeta,
'onReply': onReply,
'rendered': true,
'initComment': targetComment,
'initReplyThread': startThread,
'config': configJso,
'messages': msgs
};
var render = function() {
if (window.goog && window.goog.comments) {
var holder = document.getElementById('comment-holder');
window.goog.comments.render(holder, provider);
}
};
// render now, or queue to render when library loads:
if (window.goog && window.goog.comments) {
render();
} else {
window.goog = window.goog || {};
window.goog.comments = window.goog.comments || {};
window.goog.comments.loadQueue = window.goog.comments.loadQueue || [];
window.goog.comments.loadQueue.push(render);
}
})();
// ]]>
</script>
<div id='comment-holder'>
<div class="comment-thread toplevel-thread"><ol id="top-ra"><li class="comment" id="c1884532463371452733"><div class="avatar-image-container"><img src="//www.blogger.com/img/blogger_logo_round_35.png" alt=""/></div><div class="comment-block"><div class="comment-header"><cite class="user"><a href="https://draft.blogger.com/profile/04941109644616714019" rel="nofollow">Maxim Smyatkin</a></cite><span class="icon user "></span><span class="datetime secondary-text"><a rel="nofollow" href="http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html?showComment=1491733255478#c1884532463371452733">April 9, 2017 at 3:20&#8239;AM</a></span></div><p class="comment-content">Very good to see the new article here after quite a long time :)</p><span class="comment-actions secondary-text"><a class="comment-reply" target="_self" data-comment-id="1884532463371452733">Reply</a><span class="item-control blog-admin blog-admin pid-133356192"><a target="_self" href="https://draft.blogger.com/comment/delete/8899645800948009496/1884532463371452733">Delete</a></span></span></div><div class="comment-replies"><div id="c1884532463371452733-rt" class="comment-thread inline-thread hidden"><span class="thread-toggle thread-expanded"><span class="thread-arrow"></span><span class="thread-count"><a target="_self">Replies</a></span></span><ol id="c1884532463371452733-ra" class="thread-chrome thread-expanded"><div></div><div id="c1884532463371452733-continue" class="continue"><a class="comment-reply" target="_self" data-comment-id="1884532463371452733">Reply</a></div></ol></div></div><div class="comment-replybox-single" id="c1884532463371452733-ce"></div></li></ol><div id="top-continue" class="continue"><a class="comment-reply" target="_self">Add comment</a></div><div class="comment-replybox-thread" id="top-ce"></div><div class="loadmore hidden" data-post-id="6145769827958755916"><a target="_self">Load more...</a></div></div>
</div>
</div>
<p class='comment-footer'>
<div class='comment-form'>
<a name='comment-form'></a>
<p>
</p>
<a href='https://draft.blogger.com/comment/frame/8899645800948009496?po=6145769827958755916&hl=en&saa=85391&origin=http://dbmsmusings.blogspot.com' id='comment-editor-src'></a>
<iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' frameborder='0' height='410px' id='comment-editor' name='comment-editor' src='' width='100%'></iframe>
<script src='https://www.blogger.com/static/v1/jsbin/3790099508-comment_from_post_iframe.js' type='text/javascript'></script>
<script type='text/javascript'>
BLOG_CMT_createIframe('https://draft.blogger.com/rpc_relay.html');
</script>
</div>
</p>
<div id='backlinks-container'>
<div id='Blog1_backlinks-container'>
</div>
</div>
</div>
</div>
</div></div>
</div>
<div class='blog-pager' id='blog-pager'>
<span id='blog-pager-newer-link'>
<a class='blog-pager-newer-link' href='http://dbmsmusings.blogspot.com/2017/10/hazelcast-and-mythical-paec-system.html' id='Blog1_blog-pager-newer-link' title='Newer Post'>Newer Post</a>
</span>
<span id='blog-pager-older-link'>
<a class='blog-pager-older-link' href='http://dbmsmusings.blogspot.com/2015/10/why-mongodb-cassandra-hbase-dynamodb_28.html' id='Blog1_blog-pager-older-link' title='Older Post'>Older Post</a>
</span>
<a class='home-link' href='http://dbmsmusings.blogspot.com/'>Home</a>
</div>
<div class='clear'></div>
<div class='post-feeds'>
<div class='feed-links'>
Subscribe to:
<a class='feed-link' href='http://dbmsmusings.blogspot.com/feeds/6145769827958755916/comments/default' target='_blank' type='application/atom+xml'>Post Comments (Atom)</a>
</div>
</div>
</div></div>
</div>
</div>
<div class='column-left-outer'>
<div class='column-left-inner'>
<aside>
</aside>
</div>
</div>
<div class='column-right-outer'>
<div class='column-right-inner'>
<aside>
<div class='sidebar section' id='sidebar-right-1'><div class='widget Image' data-version='1' id='Image1'>
<h2>Daniel Abadi</h2>
<div class='widget-content'>
<img alt='Daniel Abadi' height='449' id='Image1_img' src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjq7IZ-b9X74S5hxbSo0XZg6tWgFnU-Tkkg2SrZbH0sRSvLi37d5oAaTx5gj3DQG6jxEcvzmQIyduk9EiMPxzlvHVgl33-67YLUpDn-ns_DrXBNbQxKRAx1EDfjo5kmrW1qGIhnxdJgZw/s1600/dan_2019.jpg' width='315'/>
<br/>
</div>
<div class='clear'></div>
</div><div class='widget Profile' data-version='1' id='Profile1'>
<h2>About Me</h2>
<div class='widget-content'>
<dl class='profile-datablock'>
<dt class='profile-data'>
<a class='profile-name-link g-profile' href='https://draft.blogger.com/profile/16753133043157018521' rel='author' style='background-image: url(//draft.blogger.com/img/logo-16.png);'>
Daniel Abadi
</a>
</dt>
<dd class='profile-textblock'>Daniel Abadi is the Darnell-Kanal Professor of Computer Science at University of Maryland, College Park. He is best-known for the development of the storage and query execution engines of the C-Store (column-oriented database) prototype, which was commercialized by Vertica and eventually acquired by Hewlett-Packard in 2011, for his HadoopDB research on fault tolerant scalable analytical database systems which was commercialized by Hadapt and acquired by Teradata in 2014, and deterministic, scalable, transactional, distributed systems such as Calvin which is currently being commercialized by <a href="https://fauna.com/">Fauna</a>. Abadi has been a recipient of a
Churchill Scholarship, a NSF CAREER Award, a Sloan Research Fellowship, a VLDB Best Paper Award, two VLDB <b>10 year</b> Best Paper Awards, the 2008 SIGMOD Jim Gray Doctoral Dissertation Award, the 2013-2014 Yale Provost's Teaching Prize, and the 2013 VLDB Early Career Researcher Award. He received his PhD in 2008 from MIT.
He blogs at <a href="http://dbmsmusings.blogspot.com">DBMS Musings</a> and tweets at <a href="http://www.twitter.com/daniel_abadi">@daniel_abadi</a>.</dd>
</dl>
<a class='profile-link' href='https://draft.blogger.com/profile/16753133043157018521' rel='author'>View my complete profile</a>
<div class='clear'></div>
</div>
</div></div>
<table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'>
<tbody>
<tr>
<td class='first columns-cell'>
<div class='sidebar section' id='sidebar-right-2-1'><div class='widget BlogArchive' data-version='1' id='BlogArchive1'>
<h2>Blog Archive</h2>
<div class='widget-content'>
<div id='ArchiveList'>
<div id='BlogArchive1_ArchiveList'>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2021/'>
2021
</a>
<span class='post-count' dir='ltr'>(1)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2021/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/'>
2019
</a>
<span class='post-count' dir='ltr'>(8)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/08/'>
August
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/07/'>
July
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/06/'>
June
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2019/01/'>
January
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/'>
2018
</a>
<span class='post-count' dir='ltr'>(3)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/09/'>
September
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2018/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate expanded'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy toggle-open'>
&#9660;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/'>
2017
</a>
<span class='post-count' dir='ltr'>(3)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/10/'>
October
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate expanded'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy toggle-open'>
&#9660;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2017/04/'>
April
</a>
<span class='post-count' dir='ltr'>(1)</span>
<ul class='posts'>
<li><a href='http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html'>Distributed consistency at scale: Spanner vs. Calvin</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2015/'>
2015
</a>
<span class='post-count' dir='ltr'>(1)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2015/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/'>
2012
</a>
<span class='post-count' dir='ltr'>(4)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/11/'>
November
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/06/'>
June
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2012/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/'>
2011
</a>
<span class='post-count' dir='ltr'>(6)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/10/'>
October
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/07/'>
July
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/05/'>
May
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2011/02/'>
February
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/'>
2010
</a>
<span class='post-count' dir='ltr'>(8)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/08/'>
August
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/07/'>
July
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/04/'>
April
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/03/'>
March
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2010/01/'>
January
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/'>
2009
</a>
<span class='post-count' dir='ltr'>(21)</span>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/12/'>
December
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/11/'>
November
</a>
<span class='post-count' dir='ltr'>(1)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/10/'>
October
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/09/'>
September
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/08/'>
August
</a>
<span class='post-count' dir='ltr'>(2)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/07/'>
July
</a>
<span class='post-count' dir='ltr'>(5)</span>
</li>
</ul>
<ul class='hierarchy'>
<li class='archivedate collapsed'>
<a class='toggle' href='javascript:void(0)'>
<span class='zippy'>
&#9658;&#160;
</span>
</a>
<a class='post-count-link' href='http://dbmsmusings.blogspot.com/2009/06/'>
June
</a>
<span class='post-count' dir='ltr'>(8)</span>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class='clear'></div>
</div>
</div></div>
</td>
<td class='columns-cell'>
<div class='sidebar section' id='sidebar-right-2-2'><div class='widget Followers' data-version='1' id='Followers1'>
<h2 class='title'>Followers</h2>
<div class='widget-content'>
<div id='Followers1-wrapper'>
<div style='margin-right:2px;'>
<div><script type="text/javascript" src="https://apis.google.com/js/platform.js"></script>
<div id="followers-iframe-container"></div>
<script type="text/javascript">
window.followersIframe = null;
function followersIframeOpen(url) {
gapi.load("gapi.iframes", function() {
if (gapi.iframes && gapi.iframes.getContext) {
window.followersIframe = gapi.iframes.getContext().openChild({
url: url,
where: document.getElementById("followers-iframe-container"),
messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER,
messageHandlers: {
'_ready': function(obj) {
window.followersIframe.getIframeEl().height = obj.height;
},
'reset': function() {
window.followersIframe.close();
followersIframeOpen("https://draft.blogger.com/followers/frame/8899645800948009496?colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByM2NjY2NjYiByMyMTk4YTYqByNmZmZmZmYyByM2NjY2NjY6ByM2NjY2NjZCByMyMTk4YTZKByNjY2NjY2NSByMyMTk4YTZaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26hl\x3den\x26origin\x3dhttp://dbmsmusings.blogspot.com");
},
'open': function(url) {
window.followersIframe.close();
followersIframeOpen(url);
}
}
});
}
});
}
followersIframeOpen("https://draft.blogger.com/followers/frame/8899645800948009496?colors\x3dCgt0cmFuc3BhcmVudBILdHJhbnNwYXJlbnQaByM2NjY2NjYiByMyMTk4YTYqByNmZmZmZmYyByM2NjY2NjY6ByM2NjY2NjZCByMyMTk4YTZKByNjY2NjY2NSByMyMTk4YTZaC3RyYW5zcGFyZW50\x26pageSize\x3d21\x26hl\x3den\x26origin\x3dhttp://dbmsmusings.blogspot.com");
</script></div>
</div>
</div>
<div class='clear'></div>
</div>
</div></div>
</td>
</tr>
</tbody>
</table>
<div class='sidebar no-items section' id='sidebar-right-3'></div>
</aside>
</div>
</div>
</div>
<div style='clear: both'></div>
<!-- columns -->
</div>
<!-- main -->
</div>
</div>
<div class='main-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
<footer>
<div class='footer-outer'>
<div class='footer-cap-top cap-top'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
<div class='fauxborder-left footer-fauxborder-left'>
<div class='fauxborder-right footer-fauxborder-right'></div>
<div class='region-inner footer-inner'>
<div class='foot no-items section' id='footer-1'></div>
<table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'>
<tbody>
<tr>
<td class='first columns-cell'>
<div class='foot no-items section' id='footer-2-1'></div>
</td>
<td class='columns-cell'>
<div class='foot no-items section' id='footer-2-2'></div>
</td>
</tr>
</tbody>
</table>
<!-- outside of the include in order to lock Attribution widget -->
<div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'>
<div class='widget-content' style='text-align: center;'>
Ethereal theme. Powered by <a href='https://draft.blogger.com' target='_blank'>Blogger</a>.
</div>
<div class='clear'></div>
</div></div>
</div>
</div>
<div class='footer-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</footer>
<!-- content -->
</div>
</div>
<div class='content-cap-bottom cap-bottom'>
<div class='cap-left'></div>
<div class='cap-right'></div>
</div>
</div>
</div>
<script type='text/javascript'>
window.setTimeout(function() {
document.body.className = document.body.className.replace('loading', '');
}, 10);
</script>
<script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/851759228-widgets.js"></script>
<script type='text/javascript'>
window['__wavt'] = 'AAPvtVmTmUYhOtFIIH_LWRbaAOqL:1789170614734';_WidgetManager._Init('//draft.blogger.com/rearrange?blogID\x3d8899645800948009496','//dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html','8899645800948009496');
_WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '8899645800948009496', 'title': 'DBMS Musings', 'url': 'http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html', 'canonicalUrl': 'http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html', 'homepageUrl': 'http://dbmsmusings.blogspot.com/', 'searchUrl': 'http://dbmsmusings.blogspot.com/search', 'canonicalHomepageUrl': 'http://dbmsmusings.blogspot.com/', 'blogspotFaviconUrl': 'http://dbmsmusings.blogspot.com/favicon.ico', 'bloggerUrl': 'https://draft.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'G-WPSPKTZ8VQ', 'analytics4': true, 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22DBMS Musings - RSS\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22https://draft.blogger.com/feeds/8899645800948009496/posts/default\x22 /\x3e\n\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22DBMS Musings - Atom\x22 href\x3d\x22http://dbmsmusings.blogspot.com/feeds/6145769827958755916/comments/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/31d4351e075118ef', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'item', 'postId': '6145769827958755916', 'pageName': 'Distributed consistency at scale: Spanner vs. Calvin', 'pageTitle': 'DBMS Musings: Distributed consistency at scale: Spanner vs. Calvin'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'Ethereal', 'localizedName': 'Ethereal', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': false, 'variant': 'hummingBirds2', 'variantId': 'hummingBirds2'}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Distributed consistency at scale: Spanner vs. Calvin', 'description': ' Introduction In 2012, two research papers were published that described the design of geographically replicated, consistent, ACID complia...', 'url': 'http://dbmsmusings.blogspot.com/2017/04/distributed-consistency-at-scale.html', 'type': 'item', 'isSingleItem': true, 'isMultipleItems': false, 'isError': false, 'isPage': false, 'isPost': true, 'isHomepage': false, 'isArchive': false, 'isLabelSearch': false, 'postId': 6145769827958755916}}]);
_WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/120969204-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/828616780-lightbox_bundle.css'}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_ImageView', new _WidgetInfo('Image1', 'sidebar-right-1', document.getElementById('Image1'), {'resize': true}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar-right-1', document.getElementById('Profile1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-2-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_FollowersView', new _WidgetInfo('Followers1', 'sidebar-right-2-2', document.getElementById('Followers1'), {}, 'displayModeFull'));
_WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull'));
</script>
</body>
</html>