mirror of https://github.com/apache/cassandra
add row-level isolation via SnapTree
patch by slebresne; reviewed by jbellis for CASSANDRA-2893 git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@1225001 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1bd7b42102
commit
bad90afc6f
|
|
@ -0,0 +1,776 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<title>doc/LICENSE at master from nbronson/snaptree - GitHub</title>
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" />
|
||||
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" />
|
||||
|
||||
|
||||
|
||||
|
||||
<meta content="authenticity_token" name="csrf-param" />
|
||||
<meta content="kCKdrZvsCWGNIGaBTKBWlG4gYXwI636kkFF5Jfbr//c=" name="csrf-token" />
|
||||
|
||||
<link href="https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github-ce4abc8fb736cacb557664dcd8194a5486c74f6b.css" media="screen" rel="stylesheet" type="text/css" />
|
||||
|
||||
|
||||
<script src="https://a248.e.akamai.net/assets.github.com/javascripts/bundles/jquery-6c2aad85e5c2becfaac6d62ce0f290d10fa1725e.js" type="text/javascript"></script>
|
||||
<script src="https://a248.e.akamai.net/assets.github.com/javascripts/bundles/github-724a1478428e953614c0459ba27f5d900fc109be.js" type="text/javascript"></script>
|
||||
|
||||
|
||||
<link rel='permalink' href='/nbronson/snaptree/blob/b198f84b0c927f6b5cdef080552fc26aa004d3ee/doc/LICENSE'>
|
||||
|
||||
|
||||
<meta name="description" content="snaptree - Concurrent TreeMap w/ efficient support for clone() and consistent iteration" />
|
||||
<link href="https://github.com/nbronson/snaptree/commits/master.atom" rel="alternate" title="Recent Commits to snaptree:master" type="application/atom+xml" />
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body class="logged_out page-blob vis-public env-production ">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="header" class="true clearfix">
|
||||
<div class="container" class="clearfix">
|
||||
<a class="site-logo" href="https://github.com">
|
||||
<!--[if IE]>
|
||||
<img alt="GitHub" class="github-logo" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7.png?1323882717" />
|
||||
<img alt="GitHub" class="github-logo-hover" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7-hover.png?1324325359" />
|
||||
<![endif]-->
|
||||
<img alt="GitHub" class="github-logo-4x" height="30" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x.png?1323882717" />
|
||||
<img alt="GitHub" class="github-logo-4x-hover" height="30" src="https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x-hover.png?1324325359" />
|
||||
</a>
|
||||
|
||||
<!--
|
||||
make sure to use fully qualified URLs here since this nav
|
||||
is used on error pages on other domains
|
||||
-->
|
||||
<ul class="top-nav logged_out">
|
||||
<li class="pricing"><a href="https://github.com/plans">Signup and Pricing</a></li>
|
||||
<li class="explore"><a href="https://github.com/explore">Explore GitHub</a></li>
|
||||
<li class="features"><a href="https://github.com/features">Features</a></li>
|
||||
<li class="blog"><a href="https://github.com/blog">Blog</a></li>
|
||||
<li class="login"><a href="https://github.com/login?return_to=%2Fnbronson%2Fsnaptree%2Fblob%2Fmaster%2Fdoc%2FLICENSE">Login</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="site">
|
||||
<div class="container">
|
||||
<div class="pagehead repohead instapaper_ignore readability-menu">
|
||||
|
||||
|
||||
<div class="title-actions-bar">
|
||||
<h1>
|
||||
<a href="/nbronson">nbronson</a> /
|
||||
<strong><a href="/nbronson/snaptree" class="js-current-repository">snaptree</a></strong>
|
||||
</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
<ul class="pagehead-actions">
|
||||
|
||||
|
||||
<li><a href="/login?return_to=%2Fnbronson%2Fsnaptree" class="minibutton btn-watch watch-button entice tooltipped leftwards" rel="nofollow" title="You must be logged in to use this feature"><span><span class="icon"></span>Watch</span></a></li>
|
||||
<li><a href="/login?return_to=%2Fnbronson%2Fsnaptree" class="minibutton btn-fork fork-button entice tooltipped leftwards" rel="nofollow" title="You must be logged in to use this feature"><span><span class="icon"></span>Fork</span></a></li>
|
||||
|
||||
|
||||
<li class="repostats">
|
||||
<ul class="repo-stats">
|
||||
<li class="watchers ">
|
||||
<a href="/nbronson/snaptree/watchers" title="Watchers" class="tooltipped downwards">
|
||||
25
|
||||
</a>
|
||||
</li>
|
||||
<li class="forks">
|
||||
<a href="/nbronson/snaptree/network" title="Forks" class="tooltipped downwards">
|
||||
2
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<ul class="tabs">
|
||||
<li><a href="/nbronson/snaptree" class="selected" highlight="repo_sourcerepo_downloadsrepo_commitsrepo_tagsrepo_branches">Code</a></li>
|
||||
<li><a href="/nbronson/snaptree/network" highlight="repo_networkrepo_fork_queue">Network</a>
|
||||
<li><a href="/nbronson/snaptree/pulls" highlight="repo_pulls">Pull Requests <span class='counter'>0</span></a></li>
|
||||
|
||||
<li><a href="/nbronson/snaptree/issues" highlight="repo_issues">Issues <span class='counter'>0</span></a></li>
|
||||
|
||||
|
||||
<li><a href="/nbronson/snaptree/graphs" highlight="repo_graphsrepo_contributors">Stats & Graphs</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="frame frame-center tree-finder" style="display:none"
|
||||
data-tree-list-url="/nbronson/snaptree/tree-list/b198f84b0c927f6b5cdef080552fc26aa004d3ee"
|
||||
data-blob-url-prefix="/nbronson/snaptree/blob/b198f84b0c927f6b5cdef080552fc26aa004d3ee"
|
||||
>
|
||||
|
||||
<div class="breadcrumb">
|
||||
<b><a href="/nbronson/snaptree">snaptree</a></b> /
|
||||
<input class="tree-finder-input js-navigation-enable" type="text" name="query" autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
|
||||
<div class="octotip">
|
||||
<p>
|
||||
<a href="/nbronson/snaptree/dismiss-tree-finder-help" class="dismiss js-dismiss-tree-list-help" title="Hide this notice forever" rel="nofollow">Dismiss</a>
|
||||
<strong>Octotip:</strong> You've activated the <em>file finder</em>
|
||||
by pressing <span class="kbd">t</span> Start typing to filter the
|
||||
file list. Use <span class="kbd badmono">↑</span> and
|
||||
<span class="kbd badmono">↓</span> to navigate,
|
||||
<span class="kbd">enter</span> to view files.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<table class="tree-browser" cellpadding="0" cellspacing="0">
|
||||
<tr class="js-header"><th> </th><th>name</th></tr>
|
||||
<tr class="js-no-results no-results" style="display: none">
|
||||
<th colspan="2">No matching files</th>
|
||||
</tr>
|
||||
<tbody class="js-results-list js-navigation-container" data-navigation-enable-mouse>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="jump-to-line" style="display:none">
|
||||
<h2>Jump to Line</h2>
|
||||
<form>
|
||||
<input class="textfield" type="text">
|
||||
<div class="full-button">
|
||||
<button type="submit" class="classy">
|
||||
<span>Go</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="subnav-bar">
|
||||
|
||||
<ul class="actions">
|
||||
|
||||
<li class="switcher">
|
||||
|
||||
<div class="context-menu-container js-menu-container">
|
||||
<span class="text">Current branch:</span>
|
||||
<a href="#"
|
||||
class="minibutton bigger switcher context-menu-button js-menu-target js-commitish-button btn-branch repo-tree"
|
||||
data-master-branch="master"
|
||||
data-ref="master">
|
||||
<span><span class="icon"></span>master</span>
|
||||
</a>
|
||||
|
||||
<div class="context-pane commitish-context js-menu-content">
|
||||
<a href="javascript:;" class="close js-menu-close"></a>
|
||||
<div class="title">Switch Branches/Tags</div>
|
||||
<div class="body pane-selector commitish-selector js-filterable-commitishes">
|
||||
<div class="filterbar">
|
||||
<div class="placeholder-field js-placeholder-field">
|
||||
<label class="placeholder" for="context-commitish-filter-field" data-placeholder-mode="sticky">Filter branches/tags</label>
|
||||
<input type="text" id="context-commitish-filter-field" class="commitish-filter" />
|
||||
</div>
|
||||
|
||||
<ul class="tabs">
|
||||
<li><a href="#" data-filter="branches" class="selected">Branches</a></li>
|
||||
<li><a href="#" data-filter="tags">Tags</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="commitish-item branch-commitish selector-item">
|
||||
<h4>
|
||||
<a href="/nbronson/snaptree/blob/master/doc/LICENSE" data-name="master">master</a>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="no-results" style="display:none">Nothing to show</div>
|
||||
</div>
|
||||
</div><!-- /.commitish-context-context -->
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="subnav">
|
||||
<li><a href="/nbronson/snaptree" class="selected" highlight="repo_source">Files</a></li>
|
||||
<li><a href="/nbronson/snaptree/commits/master" highlight="repo_commits">Commits</a></li>
|
||||
<li><a href="/nbronson/snaptree/branches" class="" highlight="repo_branches" rel="nofollow">Branches <span class="counter">1</span></a></li>
|
||||
<li><a href="/nbronson/snaptree/tags" class="blank" highlight="repo_tags">Tags <span class="counter">0</span></a></li>
|
||||
<li><a href="/nbronson/snaptree/downloads" class="blank" highlight="repo_downloads">Downloads <span class="counter">0</span></a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- /.repohead -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<p class="last-commit">Latest commit to the <strong>master</strong> branch</p>
|
||||
|
||||
<div class="commit commit-tease js-details-container">
|
||||
<p class="commit-title ">
|
||||
<a href="/nbronson/snaptree/commit/b198f84b0c927f6b5cdef080552fc26aa004d3ee" class="message">update to new IDEA install</a>
|
||||
|
||||
</p>
|
||||
<div class="commit-meta">
|
||||
<a href="/nbronson/snaptree/commit/b198f84b0c927f6b5cdef080552fc26aa004d3ee" class="sha-block">commit <span class="sha">b198f84b0c</span></a>
|
||||
|
||||
<div class="authorship">
|
||||
<img class="gravatar" height="20" src="https://secure.gravatar.com/avatar/9e4674291aec6ad9f6c0a7e219d522c0?s=140&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png" width="20" />
|
||||
<span class="author-name"><a href="/nbronson">nbronson</a></span>
|
||||
authored <time class="js-relative-date" datetime="2011-11-16T09:38:04-08:00" title="2011-11-16 09:38:04">November 16, 2011</time>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="slider">
|
||||
|
||||
<div class="breadcrumb" data-path="doc/LICENSE/">
|
||||
<b><a href="/nbronson/snaptree/tree/b198f84b0c927f6b5cdef080552fc26aa004d3ee" class="js-rewrite-sha">snaptree</a></b> / <a href="/nbronson/snaptree/tree/b198f84b0c927f6b5cdef080552fc26aa004d3ee/doc" class="js-rewrite-sha">doc</a> / LICENSE <span style="display:none" id="clippy_4738" class="clippy-text">doc/LICENSE</span>
|
||||
|
||||
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
|
||||
width="110"
|
||||
height="14"
|
||||
class="clippy"
|
||||
id="clippy" >
|
||||
<param name="movie" value="https://a248.e.akamai.net/assets.github.com/flash/clippy.swf?1261951368?v5"/>
|
||||
<param name="allowScriptAccess" value="always" />
|
||||
<param name="quality" value="high" />
|
||||
<param name="scale" value="noscale" />
|
||||
<param NAME="FlashVars" value="id=clippy_4738&copied=copied!&copyto=copy to clipboard">
|
||||
<param name="bgcolor" value="#FFFFFF">
|
||||
<param name="wmode" value="opaque">
|
||||
<embed src="https://a248.e.akamai.net/assets.github.com/flash/clippy.swf?1261951368?v5"
|
||||
width="110"
|
||||
height="14"
|
||||
name="clippy"
|
||||
quality="high"
|
||||
allowScriptAccess="always"
|
||||
type="application/x-shockwave-flash"
|
||||
pluginspage="http://www.macromedia.com/go/getflashplayer"
|
||||
FlashVars="id=clippy_4738&copied=copied!&copyto=copy to clipboard"
|
||||
bgcolor="#FFFFFF"
|
||||
wmode="opaque"
|
||||
/>
|
||||
</object>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="frames">
|
||||
<div class="frame frame-center" data-path="doc/LICENSE/" data-permalink-url="/nbronson/snaptree/blob/b198f84b0c927f6b5cdef080552fc26aa004d3ee/doc/LICENSE" data-title="doc/LICENSE at master from nbronson/snaptree - GitHub" data-type="blob">
|
||||
<ul class="big-actions">
|
||||
<li><a class="file-edit-link minibutton js-rewrite-sha" href="/nbronson/snaptree/edit/b198f84b0c927f6b5cdef080552fc26aa004d3ee/doc/LICENSE" data-method="post" rel="nofollow"><span>Edit this file</span></a></li>
|
||||
</ul>
|
||||
|
||||
<div id="files">
|
||||
<div class="file">
|
||||
<div class="meta">
|
||||
<div class="info">
|
||||
<span class="icon"><img alt="Txt" height="16" src="https://a248.e.akamai.net/assets.github.com/images/icons/txt.png?1252203928" width="16" /></span>
|
||||
<span class="mode" title="File Mode">100644</span>
|
||||
<span>36 lines (27 sloc)</span>
|
||||
<span>1.715 kb</span>
|
||||
</div>
|
||||
<ul class="actions">
|
||||
<li><a href="/nbronson/snaptree/raw/master/doc/LICENSE" id="raw-url">raw</a></li>
|
||||
<li><a href="/nbronson/snaptree/blame/master/doc/LICENSE">blame</a></li>
|
||||
<li><a href="/nbronson/snaptree/commits/master/doc/LICENSE" rel="nofollow">history</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="data type-text">
|
||||
<table cellpadding="0" cellspacing="0" class="lines">
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="line_numbers"><span id="L1" rel="#L1">1</span>
|
||||
<span id="L2" rel="#L2">2</span>
|
||||
<span id="L3" rel="#L3">3</span>
|
||||
<span id="L4" rel="#L4">4</span>
|
||||
<span id="L5" rel="#L5">5</span>
|
||||
<span id="L6" rel="#L6">6</span>
|
||||
<span id="L7" rel="#L7">7</span>
|
||||
<span id="L8" rel="#L8">8</span>
|
||||
<span id="L9" rel="#L9">9</span>
|
||||
<span id="L10" rel="#L10">10</span>
|
||||
<span id="L11" rel="#L11">11</span>
|
||||
<span id="L12" rel="#L12">12</span>
|
||||
<span id="L13" rel="#L13">13</span>
|
||||
<span id="L14" rel="#L14">14</span>
|
||||
<span id="L15" rel="#L15">15</span>
|
||||
<span id="L16" rel="#L16">16</span>
|
||||
<span id="L17" rel="#L17">17</span>
|
||||
<span id="L18" rel="#L18">18</span>
|
||||
<span id="L19" rel="#L19">19</span>
|
||||
<span id="L20" rel="#L20">20</span>
|
||||
<span id="L21" rel="#L21">21</span>
|
||||
<span id="L22" rel="#L22">22</span>
|
||||
<span id="L23" rel="#L23">23</span>
|
||||
<span id="L24" rel="#L24">24</span>
|
||||
<span id="L25" rel="#L25">25</span>
|
||||
<span id="L26" rel="#L26">26</span>
|
||||
<span id="L27" rel="#L27">27</span>
|
||||
<span id="L28" rel="#L28">28</span>
|
||||
<span id="L29" rel="#L29">29</span>
|
||||
<span id="L30" rel="#L30">30</span>
|
||||
<span id="L31" rel="#L31">31</span>
|
||||
<span id="L32" rel="#L32">32</span>
|
||||
<span id="L33" rel="#L33">33</span>
|
||||
<span id="L34" rel="#L34">34</span>
|
||||
<span id="L35" rel="#L35">35</span>
|
||||
<span id="L36" rel="#L36">36</span>
|
||||
</pre>
|
||||
</td>
|
||||
<td width="100%">
|
||||
<div class="highlight"><pre><div class='line' id='LC1'>SNAPTREE LICENSE</div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'>Copyright (c) 2009 Stanford University, unless otherwise specified.</div><div class='line' id='LC4'>All rights reserved.</div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'>This software was developed by the Pervasive Parallelism Laboratory of</div><div class='line' id='LC7'>Stanford University, California, USA.</div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'>Permission to use, copy, modify, and distribute this software in source</div><div class='line' id='LC10'>or binary form for any purpose with or without fee is hereby granted,</div><div class='line' id='LC11'>provided that the following conditions are met:</div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'> 1. Redistributions of source code must retain the above copyright</div><div class='line' id='LC14'> notice, this list of conditions and the following disclaimer.</div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'> 2. Redistributions in binary form must reproduce the above copyright</div><div class='line' id='LC17'> notice, this list of conditions and the following disclaimer in the</div><div class='line' id='LC18'> documentation and/or other materials provided with the distribution.</div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'> 3. Neither the name of Stanford University nor the names of its</div><div class='line' id='LC21'> contributors may be used to endorse or promote products derived</div><div class='line' id='LC22'> from this software without specific prior written permission.</div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'>THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND</div><div class='line' id='LC26'>ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</div><div class='line' id='LC27'>IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE</div><div class='line' id='LC28'>ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE</div><div class='line' id='LC29'>FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</div><div class='line' id='LC30'>DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</div><div class='line' id='LC31'>SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</div><div class='line' id='LC32'>CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT</div><div class='line' id='LC33'>LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY</div><div class='line' id='LC34'>OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF</div><div class='line' id='LC35'>SUCH DAMAGE.</div><div class='line' id='LC36'><br/></div></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="frame frame-loading" style="display:none;" data-tree-list-url="/nbronson/snaptree/tree-list/b198f84b0c927f6b5cdef080552fc26aa004d3ee" data-blob-url-prefix="/nbronson/snaptree/blob/b198f84b0c927f6b5cdef080552fc26aa004d3ee">
|
||||
<img src="https://a248.e.akamai.net/assets.github.com/images/modules/ajax/big_spinner_336699.gif?1315937507" height="32" width="32">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- footer -->
|
||||
<div id="footer" >
|
||||
|
||||
<div class="upper_footer">
|
||||
<div class="container" class="clearfix">
|
||||
|
||||
<!--[if IE]><h4 id="blacktocat_ie">GitHub Links</h4><![endif]-->
|
||||
<![if !IE]><h4 id="blacktocat">GitHub Links</h4><![endif]>
|
||||
|
||||
<ul class="footer_nav">
|
||||
<h4>GitHub</h4>
|
||||
<li><a href="https://github.com/about">About</a></li>
|
||||
<li><a href="https://github.com/blog">Blog</a></li>
|
||||
<li><a href="https://github.com/features">Features</a></li>
|
||||
<li><a href="https://github.com/contact">Contact & Support</a></li>
|
||||
<li><a href="https://github.com/training">Training</a></li>
|
||||
<li><a href="http://enterprise.github.com/">GitHub Enterprise</a></li>
|
||||
<li><a href="http://status.github.com/">Site Status</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="footer_nav">
|
||||
<h4>Tools</h4>
|
||||
<li><a href="http://get.gaug.es/">Gauges: Analyze web traffic</a></li>
|
||||
<li><a href="http://speakerdeck.com">Speakerdeck: Presentations</a></li>
|
||||
<li><a href="https://gist.github.com">Gist: Code snippets</a></li>
|
||||
<li><a href="http://mac.github.com/">GitHub for Mac</a></li>
|
||||
<li><a href="http://mobile.github.com/">Issues for iPhone</a></li>
|
||||
<li><a href="http://jobs.github.com/">Job Board</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="footer_nav">
|
||||
<h4>Extras</h4>
|
||||
<li><a href="http://shop.github.com/">GitHub Shop</a></li>
|
||||
<li><a href="http://octodex.github.com/">The Octodex</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="footer_nav">
|
||||
<h4>Documentation</h4>
|
||||
<li><a href="http://help.github.com/">GitHub Help</a></li>
|
||||
<li><a href="http://developer.github.com/">Developer API</a></li>
|
||||
<li><a href="http://github.github.com/github-flavored-markdown/">GitHub Flavored Markdown</a></li>
|
||||
<li><a href="http://pages.github.com/">GitHub Pages</a></li>
|
||||
</ul>
|
||||
|
||||
</div><!-- /.site -->
|
||||
</div><!-- /.upper_footer -->
|
||||
|
||||
<div class="lower_footer">
|
||||
<div class="container" class="clearfix">
|
||||
<!--[if IE]><div id="legal_ie"><![endif]-->
|
||||
<![if !IE]><div id="legal"><![endif]>
|
||||
<ul>
|
||||
<li><a href="https://github.com/site/terms">Terms of Service</a></li>
|
||||
<li><a href="https://github.com/site/privacy">Privacy</a></li>
|
||||
<li><a href="https://github.com/security">Security</a></li>
|
||||
</ul>
|
||||
|
||||
<p>© 2011 <span id="_rrt" title="0.07115s from fe10.rs.github.com">GitHub</span> Inc. All rights reserved.</p>
|
||||
</div><!-- /#legal or /#legal_ie-->
|
||||
|
||||
<div class="sponsor">
|
||||
<a href="http://www.rackspace.com" class="logo">
|
||||
<img alt="Dedicated Server" height="36" src="https://a248.e.akamai.net/assets.github.com/images/modules/footer/rackspace_logo.png?v2" width="38" />
|
||||
</a>
|
||||
Powered by the <a href="http://www.rackspace.com ">Dedicated
|
||||
Servers</a> and<br/> <a href="http://www.rackspacecloud.com">Cloud
|
||||
Computing</a> of Rackspace Hosting<span>®</span>
|
||||
</div>
|
||||
</div><!-- /.site -->
|
||||
</div><!-- /.lower_footer -->
|
||||
|
||||
</div><!-- /#footer -->
|
||||
|
||||
|
||||
|
||||
<div id="keyboard_shortcuts_pane" class="instapaper_ignore readability-extra" style="display:none">
|
||||
<h2>Keyboard Shortcuts <small><a href="#" class="js-see-all-keyboard-shortcuts">(see all)</a></small></h2>
|
||||
|
||||
<div class="columns threecols">
|
||||
<div class="column first">
|
||||
<h3>Site wide shortcuts</h3>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>s</dt>
|
||||
<dd>Focus site search</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>?</dt>
|
||||
<dd>Bring up this help dialog</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.first -->
|
||||
|
||||
<div class="column middle" style='display:none'>
|
||||
<h3>Commit list</h3>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>j</dt>
|
||||
<dd>Move selection down</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>k</dt>
|
||||
<dd>Move selection up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>c <em>or</em> o <em>or</em> enter</dt>
|
||||
<dd>Open commit</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>y</dt>
|
||||
<dd>Expand URL to its canonical form</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.first -->
|
||||
|
||||
<div class="column last" style='display:none'>
|
||||
<h3>Pull request list</h3>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>j</dt>
|
||||
<dd>Move selection down</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>k</dt>
|
||||
<dd>Move selection up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>o <em>or</em> enter</dt>
|
||||
<dd>Open issue</dd>
|
||||
</dl>
|
||||
</div><!-- /.columns.last -->
|
||||
|
||||
</div><!-- /.columns.equacols -->
|
||||
|
||||
<div style='display:none'>
|
||||
<div class="rule"></div>
|
||||
|
||||
<h3>Issues</h3>
|
||||
|
||||
<div class="columns threecols">
|
||||
<div class="column first">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>j</dt>
|
||||
<dd>Move selection down</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>k</dt>
|
||||
<dd>Move selection up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>x</dt>
|
||||
<dd>Toggle selection</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>o <em>or</em> enter</dt>
|
||||
<dd>Open issue</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.first -->
|
||||
<div class="column middle">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>I</dt>
|
||||
<dd>Mark selection as read</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>U</dt>
|
||||
<dd>Mark selection as unread</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>e</dt>
|
||||
<dd>Close selection</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>y</dt>
|
||||
<dd>Remove selection from view</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.middle -->
|
||||
<div class="column last">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>c</dt>
|
||||
<dd>Create issue</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>l</dt>
|
||||
<dd>Create label</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>i</dt>
|
||||
<dd>Back to inbox</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>u</dt>
|
||||
<dd>Back to issues</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>/</dt>
|
||||
<dd>Focus issues search</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style='display:none'>
|
||||
<div class="rule"></div>
|
||||
|
||||
<h3>Issues Dashboard</h3>
|
||||
|
||||
<div class="columns threecols">
|
||||
<div class="column first">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>j</dt>
|
||||
<dd>Move selection down</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>k</dt>
|
||||
<dd>Move selection up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>o <em>or</em> enter</dt>
|
||||
<dd>Open issue</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.first -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style='display:none'>
|
||||
<div class="rule"></div>
|
||||
|
||||
<h3>Network Graph</h3>
|
||||
<div class="columns equacols">
|
||||
<div class="column first">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt><span class="badmono">←</span> <em>or</em> h</dt>
|
||||
<dd>Scroll left</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt><span class="badmono">→</span> <em>or</em> l</dt>
|
||||
<dd>Scroll right</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt><span class="badmono">↑</span> <em>or</em> k</dt>
|
||||
<dd>Scroll up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt><span class="badmono">↓</span> <em>or</em> j</dt>
|
||||
<dd>Scroll down</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>t</dt>
|
||||
<dd>Toggle visibility of head labels</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.first -->
|
||||
<div class="column last">
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>shift <span class="badmono">←</span> <em>or</em> shift h</dt>
|
||||
<dd>Scroll all the way left</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>shift <span class="badmono">→</span> <em>or</em> shift l</dt>
|
||||
<dd>Scroll all the way right</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>shift <span class="badmono">↑</span> <em>or</em> shift k</dt>
|
||||
<dd>Scroll all the way up</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>shift <span class="badmono">↓</span> <em>or</em> shift j</dt>
|
||||
<dd>Scroll all the way down</dd>
|
||||
</dl>
|
||||
</div><!-- /.column.last -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div >
|
||||
<div class="rule"></div>
|
||||
<div class="columns threecols">
|
||||
<div class="column first" >
|
||||
<h3>Source Code Browsing</h3>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>t</dt>
|
||||
<dd>Activates the file finder</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>l</dt>
|
||||
<dd>Jump to line</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>w</dt>
|
||||
<dd>Switch branch/tag</dd>
|
||||
</dl>
|
||||
<dl class="keyboard-mappings">
|
||||
<dt>y</dt>
|
||||
<dd>Expand URL to its canonical form</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="markdown-help" class="instapaper_ignore readability-extra">
|
||||
<h2>Markdown Cheat Sheet</h2>
|
||||
|
||||
<div class="cheatsheet-content">
|
||||
|
||||
<div class="mod">
|
||||
<div class="col">
|
||||
<h3>Format Text</h3>
|
||||
<p>Headers</p>
|
||||
<pre>
|
||||
# This is an <h1> tag
|
||||
## This is an <h2> tag
|
||||
###### This is an <h6> tag</pre>
|
||||
<p>Text styles</p>
|
||||
<pre>
|
||||
*This text will be italic*
|
||||
_This will also be italic_
|
||||
**This text will be bold**
|
||||
__This will also be bold__
|
||||
|
||||
*You **can** combine them*
|
||||
</pre>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h3>Lists</h3>
|
||||
<p>Unordered</p>
|
||||
<pre>
|
||||
* Item 1
|
||||
* Item 2
|
||||
* Item 2a
|
||||
* Item 2b</pre>
|
||||
<p>Ordered</p>
|
||||
<pre>
|
||||
1. Item 1
|
||||
2. Item 2
|
||||
3. Item 3
|
||||
* Item 3a
|
||||
* Item 3b</pre>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h3>Miscellaneous</h3>
|
||||
<p>Images</p>
|
||||
<pre>
|
||||

|
||||
Format: 
|
||||
</pre>
|
||||
<p>Links</p>
|
||||
<pre>
|
||||
http://github.com - automatic!
|
||||
[GitHub](http://github.com)</pre>
|
||||
<p>Blockquotes</p>
|
||||
<pre>
|
||||
As Kanye West said:
|
||||
|
||||
> We're living the future so
|
||||
> the present is our past.
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule"></div>
|
||||
|
||||
<h3>Code Examples in Markdown</h3>
|
||||
<div class="col">
|
||||
<p>Syntax highlighting with <a href="http://github.github.com/github-flavored-markdown/" title="GitHub Flavored Markdown" target="_blank">GFM</a></p>
|
||||
<pre>
|
||||
```javascript
|
||||
function fancyAlert(arg) {
|
||||
if(arg) {
|
||||
$.facebox({div:'#foo'})
|
||||
}
|
||||
}
|
||||
```</pre>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p>Or, indent your code 4 spaces</p>
|
||||
<pre>
|
||||
Here is a Python code example
|
||||
without syntax highlighting:
|
||||
|
||||
def foo:
|
||||
if not bar:
|
||||
return true</pre>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p>Inline code for comments</p>
|
||||
<pre>
|
||||
I think you should use an
|
||||
`<addr>` element here instead.</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="context-overlay"></div>
|
||||
|
||||
<div class="ajax-error-message">
|
||||
<p><span class="icon"></span> Something went wrong with that request. Please try again. <a href="javascript:;" class="ajax-error-dismiss">Dismiss</a></p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
|
@ -18,31 +18,24 @@
|
|||
package org.apache.cassandra.db;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.config.CFMetaData;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.filter.QueryPath;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.io.util.IIterableColumns;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.HeapAllocator;
|
||||
|
||||
public abstract class AbstractColumnContainer implements IColumnContainer, IIterableColumns
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(AbstractColumnContainer.class);
|
||||
|
||||
protected final AtomicReference<DeletionInfo> deletionInfo = new AtomicReference<DeletionInfo>(new DeletionInfo());
|
||||
protected final ISortedColumns columns;
|
||||
|
||||
protected AbstractColumnContainer(ISortedColumns columns)
|
||||
|
|
@ -53,20 +46,12 @@ public abstract class AbstractColumnContainer implements IColumnContainer, IIter
|
|||
@Deprecated // TODO this is a hack to set initial value outside constructor
|
||||
public void delete(int localtime, long timestamp)
|
||||
{
|
||||
deletionInfo.set(new DeletionInfo(timestamp, localtime));
|
||||
columns.delete(new ISortedColumns.DeletionInfo(timestamp, localtime));
|
||||
}
|
||||
|
||||
public void delete(AbstractColumnContainer cc2)
|
||||
{
|
||||
// Keeping deletion info for max markedForDeleteAt value
|
||||
DeletionInfo current;
|
||||
DeletionInfo cc2Info = cc2.deletionInfo.get();
|
||||
while (true)
|
||||
{
|
||||
current = deletionInfo.get();
|
||||
if (current.markedForDeleteAt >= cc2Info.markedForDeleteAt || deletionInfo.compareAndSet(current, cc2Info))
|
||||
break;
|
||||
}
|
||||
columns.delete(cc2.columns.getDeletionInfo());
|
||||
}
|
||||
|
||||
public boolean isMarkedForDelete()
|
||||
|
|
@ -76,12 +61,12 @@ public abstract class AbstractColumnContainer implements IColumnContainer, IIter
|
|||
|
||||
public long getMarkedForDeleteAt()
|
||||
{
|
||||
return deletionInfo.get().markedForDeleteAt;
|
||||
return columns.getDeletionInfo().markedForDeleteAt;
|
||||
}
|
||||
|
||||
public int getLocalDeletionTime()
|
||||
{
|
||||
return deletionInfo.get().localDeletionTime;
|
||||
return columns.getDeletionInfo().localDeletionTime;
|
||||
}
|
||||
|
||||
public AbstractType getComparator()
|
||||
|
|
@ -96,27 +81,20 @@ public abstract class AbstractColumnContainer implements IColumnContainer, IIter
|
|||
*/
|
||||
public void maybeResetDeletionTimes(int gcBefore)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
DeletionInfo current = deletionInfo.get();
|
||||
// Stop if either we don't need to change the deletion info (it's
|
||||
// still MIN_VALUE or not expired yet) or we've succesfully changed it
|
||||
if (current.localDeletionTime == Integer.MIN_VALUE
|
||||
|| current.localDeletionTime > gcBefore
|
||||
|| deletionInfo.compareAndSet(current, new DeletionInfo()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
columns.maybeResetDeletionTimes(gcBefore);
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to go through each column in the column container and resolve it before adding
|
||||
*/
|
||||
public void addAll(AbstractColumnContainer cc, Allocator allocator, Function<IColumn, IColumn> transformation)
|
||||
{
|
||||
columns.addAll(cc.columns, allocator, transformation);
|
||||
}
|
||||
|
||||
public void addAll(AbstractColumnContainer cc, Allocator allocator)
|
||||
{
|
||||
columns.addAll(cc.columns, allocator);
|
||||
delete(cc);
|
||||
addAll(cc, allocator, Functions.<IColumn>identity());
|
||||
}
|
||||
|
||||
public void addColumn(IColumn column)
|
||||
|
|
@ -166,39 +144,7 @@ public abstract class AbstractColumnContainer implements IColumnContainer, IIter
|
|||
|
||||
public void retainAll(AbstractColumnContainer container)
|
||||
{
|
||||
Iterator<IColumn> iter = iterator();
|
||||
Iterator<IColumn> toRetain = container.iterator();
|
||||
IColumn current = iter.hasNext() ? iter.next() : null;
|
||||
IColumn retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
AbstractType comparator = getComparator();
|
||||
while (current != null && retain != null)
|
||||
{
|
||||
int c = comparator.compare(current.name(), retain.name());
|
||||
if (c == 0)
|
||||
{
|
||||
if (current instanceof SuperColumn)
|
||||
{
|
||||
assert retain instanceof SuperColumn;
|
||||
((SuperColumn)current).retainAll((SuperColumn)retain);
|
||||
}
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
else if (c < 0)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
else // c > 0
|
||||
{
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
}
|
||||
while (current != null)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
columns.retainAll(container.columns);
|
||||
}
|
||||
|
||||
public int getColumnCount()
|
||||
|
|
@ -249,23 +195,6 @@ public abstract class AbstractColumnContainer implements IColumnContainer, IIter
|
|||
return columns.reverseIterator(start);
|
||||
}
|
||||
|
||||
protected static class DeletionInfo
|
||||
{
|
||||
public final long markedForDeleteAt;
|
||||
public final int localDeletionTime;
|
||||
|
||||
public DeletionInfo()
|
||||
{
|
||||
this(Long.MIN_VALUE, Integer.MIN_VALUE);
|
||||
}
|
||||
|
||||
public DeletionInfo(long markedForDeleteAt, int localDeletionTime)
|
||||
{
|
||||
this.markedForDeleteAt = markedForDeleteAt;
|
||||
this.localDeletionTime = localDeletionTime;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasExpiredTombstones(int gcBefore)
|
||||
{
|
||||
if (isMarkedForDelete() && getLocalDeletionTime() < gcBefore)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
||||
public abstract class AbstractThreadUnsafeSortedColumns implements ISortedColumns
|
||||
{
|
||||
private DeletionInfo deletionInfo;
|
||||
|
||||
public AbstractThreadUnsafeSortedColumns()
|
||||
{
|
||||
deletionInfo = new DeletionInfo();
|
||||
}
|
||||
|
||||
public DeletionInfo getDeletionInfo()
|
||||
{
|
||||
return deletionInfo;
|
||||
}
|
||||
|
||||
public void delete(DeletionInfo newInfo)
|
||||
{
|
||||
if (deletionInfo.markedForDeleteAt < newInfo.markedForDeleteAt)
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
deletionInfo = newInfo;
|
||||
}
|
||||
|
||||
public void maybeResetDeletionTimes(int gcBefore)
|
||||
{
|
||||
// Update if it's not MIN_VALUE anymore and it has expired
|
||||
if (deletionInfo.localDeletionTime != Integer.MIN_VALUE && deletionInfo.localDeletionTime <= gcBefore)
|
||||
deletionInfo = new DeletionInfo();
|
||||
}
|
||||
|
||||
public void retainAll(ISortedColumns columns)
|
||||
{
|
||||
Iterator<IColumn> iter = iterator();
|
||||
Iterator<IColumn> toRetain = columns.iterator();
|
||||
IColumn current = iter.hasNext() ? iter.next() : null;
|
||||
IColumn retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
AbstractType comparator = getComparator();
|
||||
while (current != null && retain != null)
|
||||
{
|
||||
int c = comparator.compare(current.name(), retain.name());
|
||||
if (c == 0)
|
||||
{
|
||||
if (current instanceof SuperColumn)
|
||||
{
|
||||
assert retain instanceof SuperColumn;
|
||||
((SuperColumn)current).retainAll((SuperColumn)retain);
|
||||
}
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
else if (c < 0)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
else // c > 0
|
||||
{
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
}
|
||||
while (current != null)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations should implement this rather than addAll to avoid
|
||||
// having to care about the deletion infos
|
||||
protected abstract void addAllColumns(ISortedColumns columns, Allocator allocator, Function<IColumn, IColumn> transformation);
|
||||
|
||||
public void addAll(ISortedColumns columns, Allocator allocator, Function<IColumn, IColumn> transformation)
|
||||
{
|
||||
addAllColumns(columns, allocator, transformation);
|
||||
delete(columns.getDeletionInfo());
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
public int getEstimatedColumnCount()
|
||||
{
|
||||
return size();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ package org.apache.cassandra.db;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
||||
|
|
@ -30,10 +32,11 @@ import org.apache.cassandra.utils.Allocator;
|
|||
* main operations performed are iterating over the map and adding columns
|
||||
* (especially if insertion is in sorted order).
|
||||
*/
|
||||
public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISortedColumns
|
||||
public class ArrayBackedSortedColumns extends AbstractThreadUnsafeSortedColumns implements ISortedColumns
|
||||
{
|
||||
private final AbstractType<?> comparator;
|
||||
private final boolean reversed;
|
||||
private final ArrayList<IColumn> columns;
|
||||
|
||||
public static final ISortedColumns.Factory factory = new Factory()
|
||||
{
|
||||
|
|
@ -58,13 +61,14 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
super();
|
||||
this.comparator = comparator;
|
||||
this.reversed = reversed;
|
||||
this.columns = new ArrayList<IColumn>();
|
||||
}
|
||||
|
||||
private ArrayBackedSortedColumns(Collection<IColumn> columns, AbstractType<?> comparator, boolean reversed)
|
||||
{
|
||||
super(columns);
|
||||
this.comparator = comparator;
|
||||
this.reversed = reversed;
|
||||
this.columns = new ArrayList<IColumn>(columns);
|
||||
}
|
||||
|
||||
public ISortedColumns.Factory getFactory()
|
||||
|
|
@ -79,7 +83,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
|
||||
public ISortedColumns cloneMe()
|
||||
{
|
||||
return new ArrayBackedSortedColumns(this, comparator, reversed);
|
||||
return new ArrayBackedSortedColumns(columns, comparator, reversed);
|
||||
}
|
||||
|
||||
public boolean isInsertReversed()
|
||||
|
|
@ -98,7 +102,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
public IColumn getColumn(ByteBuffer name)
|
||||
{
|
||||
int pos = binarySearch(name);
|
||||
return pos >= 0 ? get(pos) : null;
|
||||
return pos >= 0 ? columns.get(pos) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,14 +117,14 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
*/
|
||||
public void addColumn(IColumn column, Allocator allocator)
|
||||
{
|
||||
if (isEmpty())
|
||||
if (columns.isEmpty())
|
||||
{
|
||||
add(column);
|
||||
columns.add(column);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fast path if inserting at the tail
|
||||
int c = compare(get(size() - 1).name(), column.name());
|
||||
int c = compare(columns.get(size() - 1).name(), column.name());
|
||||
// note that we want an assertion here (see addColumn javadoc), but we also want that if
|
||||
// assertion are disabled, addColumn works correctly with unsorted input
|
||||
assert c <= 0 : "Added column does not sort as the " + (reversed ? "first" : "last") + " column";
|
||||
|
|
@ -128,7 +132,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
if (c < 0)
|
||||
{
|
||||
// Insert as last
|
||||
add(column);
|
||||
columns.add(column);
|
||||
}
|
||||
else if (c == 0)
|
||||
{
|
||||
|
|
@ -141,7 +145,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
if (pos >= 0)
|
||||
resolveAgainst(pos, column, allocator);
|
||||
else
|
||||
add(-pos-1, column);
|
||||
columns.add(-pos-1, column);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +155,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
*/
|
||||
private void resolveAgainst(int i, IColumn column, Allocator allocator)
|
||||
{
|
||||
IColumn oldColumn = get(i);
|
||||
IColumn oldColumn = columns.get(i);
|
||||
if (oldColumn instanceof SuperColumn)
|
||||
{
|
||||
// Delegated to SuperColumn
|
||||
|
|
@ -162,7 +166,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
{
|
||||
// calculate reconciled col from old (existing) col and new col
|
||||
IColumn reconciledColumn = column.reconcile(oldColumn, allocator);
|
||||
set(i, reconciledColumn);
|
||||
columns.set(i, reconciledColumn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +185,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
while (low <= high)
|
||||
{
|
||||
mid = (low + high) >> 1;
|
||||
if ((result = compare(name, get(mid).name())) > 0)
|
||||
if ((result = compare(name, columns.get(mid).name())) > 0)
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
|
|
@ -197,46 +201,46 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
return -mid - (result < 0 ? 1 : 2);
|
||||
}
|
||||
|
||||
public void addAll(ISortedColumns cm, Allocator allocator)
|
||||
protected void addAllColumns(ISortedColumns cm, Allocator allocator, Function<IColumn, IColumn> transformation)
|
||||
{
|
||||
if (cm.isEmpty())
|
||||
return;
|
||||
|
||||
IColumn[] copy = toArray(new IColumn[size()]);
|
||||
IColumn[] copy = columns.toArray(new IColumn[size()]);
|
||||
int idx = 0;
|
||||
Iterator<IColumn> other = reversed ? cm.reverseIterator() : cm.iterator();
|
||||
IColumn otherColumn = other.next();
|
||||
|
||||
clear();
|
||||
columns.clear();
|
||||
|
||||
while (idx < copy.length && otherColumn != null)
|
||||
{
|
||||
int c = compare(copy[idx].name(), otherColumn.name());
|
||||
if (c < 0)
|
||||
{
|
||||
add(copy[idx]);
|
||||
columns.add(copy[idx]);
|
||||
idx++;
|
||||
}
|
||||
else if (c > 0)
|
||||
{
|
||||
add(otherColumn);
|
||||
columns.add(transformation.apply(otherColumn));
|
||||
otherColumn = other.hasNext() ? other.next() : null;
|
||||
}
|
||||
else // c == 0
|
||||
{
|
||||
add(copy[idx]);
|
||||
resolveAgainst(size() - 1, otherColumn, allocator);
|
||||
columns.add(copy[idx]);
|
||||
resolveAgainst(size() - 1, transformation.apply(otherColumn), allocator);
|
||||
idx++;
|
||||
otherColumn = other.hasNext() ? other.next() : null;
|
||||
}
|
||||
}
|
||||
while (idx < copy.length)
|
||||
{
|
||||
add(copy[idx++]);
|
||||
columns.add(copy[idx++]);
|
||||
}
|
||||
while (otherColumn != null)
|
||||
{
|
||||
add(otherColumn);
|
||||
columns.add(transformation.apply(otherColumn));
|
||||
otherColumn = other.hasNext() ? other.next() : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -249,7 +253,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
int pos = binarySearch(oldColumn.name());
|
||||
if (pos >= 0)
|
||||
{
|
||||
set(pos, newColumn);
|
||||
columns.set(pos, newColumn);
|
||||
}
|
||||
|
||||
return pos >= 0;
|
||||
|
|
@ -257,7 +261,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
|
||||
public Collection<IColumn> getSortedColumns()
|
||||
{
|
||||
return reversed ? new ReverseSortedCollection() : this;
|
||||
return reversed ? new ReverseSortedCollection() : columns;
|
||||
}
|
||||
|
||||
public Collection<IColumn> getReverseSortedColumns()
|
||||
|
|
@ -272,7 +276,17 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
{
|
||||
int pos = binarySearch(name);
|
||||
if (pos >= 0)
|
||||
remove(pos);
|
||||
columns.remove(pos);
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
columns.clear();
|
||||
}
|
||||
|
||||
public SortedSet<ByteBuffer> getColumnNames()
|
||||
|
|
@ -281,20 +295,15 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
return new ColumnNamesSet();
|
||||
}
|
||||
|
||||
public int getEstimatedColumnCount()
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<IColumn> iterator()
|
||||
{
|
||||
return reversed ? reverseInternalIterator(size()) : super.iterator();
|
||||
return reversed ? reverseInternalIterator(size()) : columns.iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator()
|
||||
{
|
||||
return reversed ? super.iterator() : reverseInternalIterator(size());
|
||||
return reversed ? columns.iterator() : reverseInternalIterator(size());
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator(ByteBuffer start)
|
||||
|
|
@ -305,7 +314,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
else if (reversed)
|
||||
// listIterator.previous() doesn't return the current element at first but the previous one
|
||||
idx++;
|
||||
return reversed ? reverseInternalIterator(idx) : listIterator(idx);
|
||||
return reversed ? reverseInternalIterator(idx) : columns.listIterator(idx);
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator(ByteBuffer start)
|
||||
|
|
@ -316,12 +325,12 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
else if (!reversed)
|
||||
// listIterator.previous() doesn't return the current element at first but the previous one
|
||||
idx++;
|
||||
return reversed ? listIterator(idx) : reverseInternalIterator(idx);
|
||||
return reversed ? columns.listIterator(idx) : reverseInternalIterator(idx);
|
||||
}
|
||||
|
||||
private Iterator<IColumn> reverseInternalIterator(int idx)
|
||||
{
|
||||
final ListIterator<IColumn> iter = listIterator(idx);
|
||||
final ListIterator<IColumn> iter = columns.listIterator(idx);
|
||||
return new Iterator<IColumn>()
|
||||
{
|
||||
public boolean hasNext()
|
||||
|
|
@ -345,7 +354,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
{
|
||||
public int size()
|
||||
{
|
||||
return ArrayBackedSortedColumns.this.size();
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator()
|
||||
|
|
@ -361,12 +370,12 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
|
||||
public IColumn next()
|
||||
{
|
||||
return ArrayBackedSortedColumns.this.get(idx--);
|
||||
return columns.get(idx--);
|
||||
}
|
||||
|
||||
public void remove()
|
||||
{
|
||||
ArrayBackedSortedColumns.this.remove(idx--);
|
||||
columns.remove(idx--);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -376,12 +385,12 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
{
|
||||
public int size()
|
||||
{
|
||||
return ArrayBackedSortedColumns.this.size();
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator()
|
||||
{
|
||||
return ArrayBackedSortedColumns.super.iterator();
|
||||
return columns.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -389,7 +398,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
{
|
||||
public int size()
|
||||
{
|
||||
return ArrayBackedSortedColumns.this.size();
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
public Iterator<ByteBuffer> iterator()
|
||||
|
|
@ -416,7 +425,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
|
||||
public Comparator<ByteBuffer> comparator()
|
||||
{
|
||||
return ArrayBackedSortedColumns.this.getComparator();
|
||||
return getComparator();
|
||||
}
|
||||
|
||||
public ByteBuffer first()
|
||||
|
|
@ -424,7 +433,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
final ArrayBackedSortedColumns outerList = ArrayBackedSortedColumns.this;
|
||||
if (outerList.isEmpty())
|
||||
throw new NoSuchElementException();
|
||||
return outerList.get(outerList.reversed ? size() - 1 : 0).name();
|
||||
return outerList.columns.get(outerList.reversed ? size() - 1 : 0).name();
|
||||
}
|
||||
|
||||
public ByteBuffer last()
|
||||
|
|
@ -432,7 +441,7 @@ public class ArrayBackedSortedColumns extends ArrayList<IColumn> implements ISor
|
|||
final ArrayBackedSortedColumns outerList = ArrayBackedSortedColumns.this;
|
||||
if (outerList.isEmpty())
|
||||
throw new NoSuchElementException();
|
||||
return outerList.get(outerList.reversed ? 0 : size() - 1).name();
|
||||
return outerList.columns.get(outerList.reversed ? 0 : size() - 1).name();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,394 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import edu.stanford.ppl.concurrent.SnapTreeMap;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
||||
|
||||
/**
|
||||
* A thread-safe and atomic ISortedColumns implementation.
|
||||
* Operations (in particular addAll) on this implemenation are atomic and
|
||||
* isolated (in the sense of ACID). Typically a addAll is guaranteed that no
|
||||
* other thread can see the state where only parts but not all columns have
|
||||
* been added.
|
||||
*
|
||||
* The implementation uses snaptree (https://github.com/nbronson/snaptree),
|
||||
* and in particular it's copy-on-write clone operation to achieve its
|
||||
* atomicity guarantee.
|
||||
*
|
||||
* WARNING: removing element through getSortedColumns().iterator() is *not*
|
||||
* isolated of other operations and could actually be fully ignored in the
|
||||
* face of a concurrent. Don't use it unless in a non-concurrent context.
|
||||
*
|
||||
* TODO: check the snaptree license make it ok to use
|
||||
*/
|
||||
public class AtomicSortedColumns implements ISortedColumns
|
||||
{
|
||||
private final AtomicReference<Holder> ref;
|
||||
|
||||
public static final ISortedColumns.Factory factory = new Factory()
|
||||
{
|
||||
public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
|
||||
{
|
||||
return new AtomicSortedColumns(comparator);
|
||||
}
|
||||
|
||||
public ISortedColumns fromSorted(SortedMap<ByteBuffer, IColumn> sortedMap, boolean insertReversed)
|
||||
{
|
||||
return new AtomicSortedColumns(sortedMap);
|
||||
}
|
||||
};
|
||||
|
||||
public static ISortedColumns.Factory factory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
private AtomicSortedColumns(AbstractType<?> comparator)
|
||||
{
|
||||
this(new Holder(comparator));
|
||||
}
|
||||
|
||||
private AtomicSortedColumns(SortedMap<ByteBuffer, IColumn> columns)
|
||||
{
|
||||
this(new Holder(columns));
|
||||
}
|
||||
|
||||
private AtomicSortedColumns(Holder holder)
|
||||
{
|
||||
this.ref = new AtomicReference<Holder>(holder);
|
||||
}
|
||||
|
||||
public AbstractType<?> getComparator()
|
||||
{
|
||||
return (AbstractType)ref.get().map.comparator();
|
||||
}
|
||||
|
||||
public ISortedColumns.Factory getFactory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
public ISortedColumns cloneMe()
|
||||
{
|
||||
return new AtomicSortedColumns(ref.get().cloneMe());
|
||||
}
|
||||
|
||||
public DeletionInfo getDeletionInfo()
|
||||
{
|
||||
return ref.get().deletionInfo;
|
||||
}
|
||||
|
||||
public void delete(DeletionInfo info)
|
||||
{
|
||||
// Keeping deletion info for max markedForDeleteAt value
|
||||
Holder current;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
if (current.deletionInfo.markedForDeleteAt >= info.markedForDeleteAt)
|
||||
break;
|
||||
}
|
||||
while (!ref.compareAndSet(current, current.with(info)));
|
||||
}
|
||||
|
||||
public void maybeResetDeletionTimes(int gcBefore)
|
||||
{
|
||||
Holder current;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
// Stop if we don't need to change the deletion info (it's still MIN_VALUE or not expired yet)
|
||||
if (current.deletionInfo.localDeletionTime == Integer.MIN_VALUE || current.deletionInfo.localDeletionTime > gcBefore)
|
||||
break;
|
||||
}
|
||||
while (!ref.compareAndSet(current, current.with(new DeletionInfo())));
|
||||
}
|
||||
|
||||
public void retainAll(ISortedColumns columns)
|
||||
{
|
||||
Holder current, modified;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
modified = current.cloneMe();
|
||||
modified.retainAll(columns);
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
}
|
||||
|
||||
public void addColumn(IColumn column, Allocator allocator)
|
||||
{
|
||||
Holder current, modified;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
modified = current.cloneMe();
|
||||
modified.addColumn(column, allocator);
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
}
|
||||
|
||||
public void addAll(ISortedColumns cm, Allocator allocator, Function<IColumn, IColumn> transformation)
|
||||
{
|
||||
/*
|
||||
* This operation needs to atomicity and isolation. To that end, we
|
||||
* add the new column to a copy of the map (a cheap O(1) snapTree
|
||||
* clone) and atomically compare and swap when everything has been
|
||||
* added. Of course, we must not forget to update the deletion times
|
||||
* too.
|
||||
* In case we are adding a lot of columns, failing the final compare
|
||||
* and swap could be expensive. To mitigate, we check we haven't been
|
||||
* beaten by another thread after every column addition. If we have,
|
||||
* we bail early, avoiding unnecessary work if possible.
|
||||
*/
|
||||
Holder current, modified;
|
||||
main_loop:
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
DeletionInfo newDelInfo = current.deletionInfo;
|
||||
if (newDelInfo.markedForDeleteAt < cm.getDeletionInfo().markedForDeleteAt)
|
||||
newDelInfo = cm.getDeletionInfo();
|
||||
modified = new Holder(current.map.clone(), newDelInfo);
|
||||
|
||||
for (IColumn column : cm.getSortedColumns())
|
||||
{
|
||||
modified.addColumn(transformation.apply(column), allocator);
|
||||
// bail early if we know we've been beaten
|
||||
if (ref.get() != current)
|
||||
continue main_loop;
|
||||
}
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
}
|
||||
|
||||
public boolean replace(IColumn oldColumn, IColumn newColumn)
|
||||
{
|
||||
if (!oldColumn.name().equals(newColumn.name()))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
Holder current, modified;
|
||||
boolean replaced;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
modified = current.cloneMe();
|
||||
replaced = modified.map.replace(oldColumn.name(), oldColumn, newColumn);
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
return replaced;
|
||||
}
|
||||
|
||||
public void removeColumn(ByteBuffer name)
|
||||
{
|
||||
Holder current, modified;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
modified = current.cloneMe();
|
||||
modified.map.remove(name);
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
Holder current, modified;
|
||||
do
|
||||
{
|
||||
current = ref.get();
|
||||
modified = current.clear();
|
||||
}
|
||||
while (!ref.compareAndSet(current, modified));
|
||||
}
|
||||
|
||||
public IColumn getColumn(ByteBuffer name)
|
||||
{
|
||||
return ref.get().map.get(name);
|
||||
}
|
||||
|
||||
public SortedSet<ByteBuffer> getColumnNames()
|
||||
{
|
||||
return ref.get().map.keySet();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getSortedColumns()
|
||||
{
|
||||
return ref.get().map.values();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getReverseSortedColumns()
|
||||
{
|
||||
return ref.get().map.descendingMap().values();
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return ref.get().map.size();
|
||||
}
|
||||
|
||||
public int getEstimatedColumnCount()
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return ref.get().map.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator()
|
||||
{
|
||||
return getSortedColumns().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator()
|
||||
{
|
||||
return getReverseSortedColumns().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator(ByteBuffer start)
|
||||
{
|
||||
return ref.get().map.tailMap(start).values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator(ByteBuffer start)
|
||||
{
|
||||
return ref.get().map.descendingMap().tailMap(start).values().iterator();
|
||||
}
|
||||
|
||||
public boolean isInsertReversed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class Holder
|
||||
{
|
||||
final SnapTreeMap<ByteBuffer, IColumn> map;
|
||||
final DeletionInfo deletionInfo;
|
||||
|
||||
Holder(AbstractType<?> comparator)
|
||||
{
|
||||
this(new SnapTreeMap<ByteBuffer, IColumn>(comparator), new DeletionInfo());
|
||||
}
|
||||
|
||||
Holder(SortedMap<ByteBuffer, IColumn> columns)
|
||||
{
|
||||
this(new SnapTreeMap<ByteBuffer, IColumn>(columns), new DeletionInfo());
|
||||
}
|
||||
|
||||
Holder(SnapTreeMap<ByteBuffer, IColumn> map, DeletionInfo deletionInfo)
|
||||
{
|
||||
this.map = map;
|
||||
this.deletionInfo = deletionInfo;
|
||||
}
|
||||
|
||||
Holder cloneMe()
|
||||
{
|
||||
return with(map.clone());
|
||||
}
|
||||
|
||||
Holder with(DeletionInfo info)
|
||||
{
|
||||
return new Holder(map, info);
|
||||
}
|
||||
|
||||
Holder with(SnapTreeMap<ByteBuffer, IColumn> newMap)
|
||||
{
|
||||
return new Holder(newMap, deletionInfo);
|
||||
}
|
||||
|
||||
// There is no point in cloning the underlying map to clear it
|
||||
// afterwards.
|
||||
Holder clear()
|
||||
{
|
||||
return new Holder(new SnapTreeMap<ByteBuffer, IColumn>(map.comparator()), deletionInfo);
|
||||
}
|
||||
|
||||
void addColumn(IColumn column, Allocator allocator)
|
||||
{
|
||||
ByteBuffer name = column.name();
|
||||
IColumn oldColumn;
|
||||
while ((oldColumn = map.putIfAbsent(name, column)) != null)
|
||||
{
|
||||
if (oldColumn instanceof SuperColumn)
|
||||
{
|
||||
assert column instanceof SuperColumn;
|
||||
((SuperColumn) oldColumn).putColumn((SuperColumn)column, allocator);
|
||||
break; // Delegated to SuperColumn
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate reconciled col from old (existing) col and new col
|
||||
IColumn reconciledColumn = column.reconcile(oldColumn, allocator);
|
||||
if (map.replace(name, oldColumn, reconciledColumn))
|
||||
break;
|
||||
|
||||
// We failed to replace column due to a concurrent update or a concurrent removal. Keep trying.
|
||||
// (Currently, concurrent removal should not happen (only updates), but let us support that anyway.)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void retainAll(ISortedColumns columns)
|
||||
{
|
||||
Iterator<IColumn> iter = map.values().iterator();
|
||||
Iterator<IColumn> toRetain = columns.iterator();
|
||||
IColumn current = iter.hasNext() ? iter.next() : null;
|
||||
IColumn retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
Comparator<? super ByteBuffer> comparator = map.comparator();
|
||||
while (current != null && retain != null)
|
||||
{
|
||||
int c = comparator.compare(current.name(), retain.name());
|
||||
if (c == 0)
|
||||
{
|
||||
if (current instanceof SuperColumn)
|
||||
{
|
||||
assert retain instanceof SuperColumn;
|
||||
((SuperColumn)current).retainAll((SuperColumn)retain);
|
||||
}
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
else if (c < 0)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
else // c > 0
|
||||
{
|
||||
retain = toRetain.hasNext() ? toRetain.next() : null;
|
||||
}
|
||||
}
|
||||
while (current != null)
|
||||
{
|
||||
iter.remove();
|
||||
current = iter.hasNext() ? iter.next() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ public class CollationController
|
|||
logger.debug("collectTimeOrderedData");
|
||||
|
||||
ISortedColumns.Factory factory = mutableColumns
|
||||
? ThreadSafeSortedColumns.factory()
|
||||
? AtomicSortedColumns.factory()
|
||||
: TreeMapBackedSortedColumns.factory();
|
||||
ColumnFamily container = ColumnFamily.create(cfs.metadata, factory, filter.filter.isReversed());
|
||||
List<IColumnIterator> iterators = new ArrayList<IColumnIterator>();
|
||||
|
|
@ -209,7 +209,7 @@ public class CollationController
|
|||
{
|
||||
logger.debug("collectAllData");
|
||||
ISortedColumns.Factory factory = mutableColumns
|
||||
? ThreadSafeSortedColumns.factory()
|
||||
? AtomicSortedColumns.factory()
|
||||
: ArrayBackedSortedColumns.factory();
|
||||
List<IColumnIterator> iterators = new ArrayList<IColumnIterator>();
|
||||
ColumnFamily returnCF = ColumnFamily.create(cfs.metadata, factory, filter.filter.isReversed());
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class ColumnFamily extends AbstractColumnContainer
|
|||
|
||||
public static ColumnFamily create(CFMetaData cfm)
|
||||
{
|
||||
return create(cfm, ThreadSafeSortedColumns.factory());
|
||||
return create(cfm, TreeMapBackedSortedColumns.factory());
|
||||
}
|
||||
|
||||
public static ColumnFamily create(CFMetaData cfm, ISortedColumns.Factory factory)
|
||||
|
|
@ -84,8 +84,7 @@ public class ColumnFamily extends AbstractColumnContainer
|
|||
public ColumnFamily cloneMeShallow(ISortedColumns.Factory factory, boolean reversedInsertOrder)
|
||||
{
|
||||
ColumnFamily cf = ColumnFamily.create(cfm, factory, reversedInsertOrder);
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
cf.deletionInfo.set(deletionInfo.get());
|
||||
cf.delete(this);
|
||||
return cf;
|
||||
}
|
||||
|
||||
|
|
@ -108,8 +107,7 @@ public class ColumnFamily extends AbstractColumnContainer
|
|||
public ColumnFamily cloneMe()
|
||||
{
|
||||
ColumnFamily cf = new ColumnFamily(cfm, columns.cloneMe());
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
cf.deletionInfo.set(deletionInfo.get());
|
||||
cf.delete(this);
|
||||
return cf;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public class ColumnFamilySerializer implements ISerializer<ColumnFamily>
|
|||
|
||||
public ColumnFamily deserialize(DataInput dis) throws IOException
|
||||
{
|
||||
return deserialize(dis, IColumnSerializer.Flag.LOCAL, ThreadSafeSortedColumns.factory());
|
||||
return deserialize(dis, IColumnSerializer.Flag.LOCAL, TreeMapBackedSortedColumns.factory());
|
||||
}
|
||||
|
||||
public ColumnFamily deserialize(DataInput dis, IColumnSerializer.Flag flag, ISortedColumns.Factory factory) throws IOException
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import java.util.Iterator;
|
|||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.io.util.IIterableColumns;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
|
@ -46,6 +48,11 @@ public interface ISortedColumns extends IIterableColumns
|
|||
*/
|
||||
public Factory getFactory();
|
||||
|
||||
public DeletionInfo getDeletionInfo();
|
||||
public void delete(DeletionInfo info);
|
||||
public void maybeResetDeletionTimes(int gcBefore);
|
||||
public void retainAll(ISortedColumns columns);
|
||||
|
||||
/**
|
||||
* Adds a column to this column map.
|
||||
* If a column with the same name is already present in the map, it will
|
||||
|
|
@ -62,7 +69,7 @@ public interface ISortedColumns extends IIterableColumns
|
|||
* </code>
|
||||
* but is potentially faster.
|
||||
*/
|
||||
public void addAll(ISortedColumns cm, Allocator allocator);
|
||||
public void addAll(ISortedColumns cm, Allocator allocator, Function<IColumn, IColumn> transformation);
|
||||
|
||||
/**
|
||||
* Replace oldColumn if present by newColumn.
|
||||
|
|
@ -161,4 +168,22 @@ public interface ISortedColumns extends IIterableColumns
|
|||
*/
|
||||
public ISortedColumns fromSorted(SortedMap<ByteBuffer, IColumn> sm, boolean insertReversed);
|
||||
}
|
||||
|
||||
public static class DeletionInfo
|
||||
{
|
||||
public final long markedForDeleteAt;
|
||||
public final int localDeletionTime;
|
||||
|
||||
public DeletionInfo()
|
||||
{
|
||||
this(Long.MIN_VALUE, Integer.MIN_VALUE);
|
||||
}
|
||||
|
||||
public DeletionInfo(long markedForDeleteAt, int localDeletionTime)
|
||||
{
|
||||
this.markedForDeleteAt = markedForDeleteAt;
|
||||
this.localDeletionTime = localDeletionTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.*;
|
|||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.PeekingIterator;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -82,7 +83,15 @@ public class Memtable
|
|||
public final ColumnFamilyStore cfs;
|
||||
private final long creationTime;
|
||||
|
||||
private SlabAllocator allocator = new SlabAllocator();
|
||||
private final SlabAllocator allocator = new SlabAllocator();
|
||||
// We really only need one column by allocator but one by memtable is not a big waste and avoids needing allocators to know about CFS
|
||||
private final Function<IColumn, IColumn> localCopyFunction = new Function<IColumn, IColumn>()
|
||||
{
|
||||
public IColumn apply(IColumn c)
|
||||
{
|
||||
return c.localCopy(cfs, allocator);
|
||||
};
|
||||
};
|
||||
|
||||
public Memtable(ColumnFamilyStore cfs)
|
||||
{
|
||||
|
|
@ -203,25 +212,19 @@ public class Memtable
|
|||
? cf.isMarkedForDelete() ? 1 : 0
|
||||
: cf.getColumnCount());
|
||||
|
||||
ColumnFamily clonedCf = columnFamilies.get(key);
|
||||
// if the row doesn't exist yet in the memtable, clone cf to our allocator.
|
||||
if (clonedCf == null)
|
||||
|
||||
ColumnFamily previous = columnFamilies.get(key);
|
||||
|
||||
if (previous == null)
|
||||
{
|
||||
clonedCf = cf.cloneMeShallow();
|
||||
for (IColumn column : cf.getSortedColumns())
|
||||
clonedCf.addColumn(column.localCopy(cfs, allocator));
|
||||
clonedCf = columnFamilies.putIfAbsent(new DecoratedKey(key.token, allocator.clone(key.key)), clonedCf);
|
||||
if (clonedCf == null)
|
||||
return;
|
||||
// else there was a race and the other thread won. fall through to updating his CF object
|
||||
ColumnFamily empty = cf.cloneMeShallow(AtomicSortedColumns.factory(), false);
|
||||
// We'll add the columns later. This avoids wasting works if we get beaten in the putIfAbsent
|
||||
previous = columnFamilies.putIfAbsent(new DecoratedKey(key.token, allocator.clone(key.key)), empty);
|
||||
if (previous == null)
|
||||
previous = empty;
|
||||
}
|
||||
|
||||
// we duplicate the funcationality of CF.resolve here to avoid having to either pass the Memtable in for
|
||||
// the cloning operation, or cloning the CF container as well as the Columns. fortunately, resolve
|
||||
// is really quite simple:
|
||||
clonedCf.delete(cf);
|
||||
for (IColumn column : cf.getSortedColumns())
|
||||
clonedCf.addColumn(column.localCopy(cfs, allocator), allocator);
|
||||
previous.addAll(cf, allocator, localCopyFunction);
|
||||
}
|
||||
|
||||
// for debugging
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class Row
|
|||
|
||||
public Row deserialize(DataInput dis, int version) throws IOException
|
||||
{
|
||||
return deserialize(dis, version, IColumnSerializer.Flag.LOCAL, ThreadSafeSortedColumns.factory());
|
||||
return deserialize(dis, version, IColumnSerializer.Flag.LOCAL, TreeMapBackedSortedColumns.factory());
|
||||
}
|
||||
|
||||
public long serializedSize(Row row, int version)
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ public class RowMutation implements IMutation, MessageProducer
|
|||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
Integer cfid = Integer.valueOf(dis.readInt());
|
||||
ColumnFamily cf = ColumnFamily.serializer().deserialize(dis, flag, ThreadSafeSortedColumns.factory());
|
||||
ColumnFamily cf = ColumnFamily.serializer().deserialize(dis, flag, TreeMapBackedSortedColumns.factory());
|
||||
modifications.put(cfid, cf);
|
||||
}
|
||||
return new RowMutation(table, key, modifications);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class SuperColumn extends AbstractColumnContainer implements IColumn
|
|||
|
||||
public SuperColumn(ByteBuffer name, AbstractType comparator)
|
||||
{
|
||||
this(name, ThreadSafeSortedColumns.factory().create(comparator, false));
|
||||
this(name, AtomicSortedColumns.factory().create(comparator, false));
|
||||
}
|
||||
|
||||
SuperColumn(ByteBuffer name, ISortedColumns columns)
|
||||
|
|
@ -69,16 +69,14 @@ public class SuperColumn extends AbstractColumnContainer implements IColumn
|
|||
public SuperColumn cloneMeShallow()
|
||||
{
|
||||
SuperColumn sc = new SuperColumn(name, getComparator());
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
sc.deletionInfo.set(deletionInfo.get());
|
||||
sc.delete(this);
|
||||
return sc;
|
||||
}
|
||||
|
||||
public IColumn cloneMe()
|
||||
{
|
||||
SuperColumn sc = new SuperColumn(name, columns.cloneMe());
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
sc.deletionInfo.set(deletionInfo.get());
|
||||
sc.delete(this);
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
|
@ -262,8 +260,7 @@ public class SuperColumn extends AbstractColumnContainer implements IColumn
|
|||
// we don't try to intern supercolumn names, because if we're using Cassandra correctly it's almost
|
||||
// certainly just going to pollute our interning map with unique, dynamic values
|
||||
SuperColumn sc = new SuperColumn(allocator.clone(name), this.getComparator());
|
||||
// since deletion info is immutable, aliasing it is fine
|
||||
sc.deletionInfo.set(deletionInfo.get());
|
||||
sc.delete(this);
|
||||
|
||||
for(IColumn c : columns)
|
||||
{
|
||||
|
|
@ -358,7 +355,7 @@ class SuperColumnSerializer implements IColumnSerializer
|
|||
int size = dis.readInt();
|
||||
ColumnSerializer serializer = Column.serializer();
|
||||
ColumnSortedMap preSortedMap = new ColumnSortedMap(comparator, serializer, dis, size, flag, expireBefore);
|
||||
SuperColumn superColumn = new SuperColumn(name, ThreadSafeSortedColumns.factory().fromSorted(preSortedMap, false));
|
||||
SuperColumn superColumn = new SuperColumn(name, AtomicSortedColumns.factory().fromSorted(preSortedMap, false));
|
||||
superColumn.delete(localDeleteTime, markedForDeleteAt);
|
||||
return superColumn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.db;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
||||
public class ThreadSafeSortedColumns extends ConcurrentSkipListMap<ByteBuffer, IColumn> implements ISortedColumns
|
||||
{
|
||||
public static final ISortedColumns.Factory factory = new Factory()
|
||||
{
|
||||
public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
|
||||
{
|
||||
return new ThreadSafeSortedColumns(comparator);
|
||||
}
|
||||
|
||||
public ISortedColumns fromSorted(SortedMap<ByteBuffer, IColumn> sortedMap, boolean insertReversed)
|
||||
{
|
||||
return new ThreadSafeSortedColumns(sortedMap);
|
||||
}
|
||||
};
|
||||
|
||||
public static ISortedColumns.Factory factory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
public AbstractType<?> getComparator()
|
||||
{
|
||||
return (AbstractType)comparator();
|
||||
}
|
||||
|
||||
private ThreadSafeSortedColumns(AbstractType<?> comparator)
|
||||
{
|
||||
super(comparator);
|
||||
}
|
||||
|
||||
private ThreadSafeSortedColumns(SortedMap<ByteBuffer, IColumn> columns)
|
||||
{
|
||||
super(columns);
|
||||
}
|
||||
|
||||
public ISortedColumns.Factory getFactory()
|
||||
{
|
||||
return factory();
|
||||
}
|
||||
|
||||
public ISortedColumns cloneMe()
|
||||
{
|
||||
return new ThreadSafeSortedColumns(this);
|
||||
}
|
||||
|
||||
public boolean isInsertReversed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we find an old column that has the same name
|
||||
* the ask it to resolve itself else add the new column
|
||||
*/
|
||||
public void addColumn(IColumn column, Allocator allocator)
|
||||
{
|
||||
ByteBuffer name = column.name();
|
||||
IColumn oldColumn;
|
||||
while ((oldColumn = putIfAbsent(name, column)) != null)
|
||||
{
|
||||
if (oldColumn instanceof SuperColumn)
|
||||
{
|
||||
assert column instanceof SuperColumn;
|
||||
((SuperColumn) oldColumn).putColumn((SuperColumn)column, allocator);
|
||||
break; // Delegated to SuperColumn
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate reconciled col from old (existing) col and new col
|
||||
IColumn reconciledColumn = column.reconcile(oldColumn, allocator);
|
||||
if (replace(name, oldColumn, reconciledColumn))
|
||||
break;
|
||||
|
||||
// We failed to replace column due to a concurrent update or a concurrent removal. Keep trying.
|
||||
// (Currently, concurrent removal should not happen (only updates), but let us support that anyway.)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to go through each column in the column container and resolve it before adding
|
||||
*/
|
||||
public void addAll(ISortedColumns cm, Allocator allocator)
|
||||
{
|
||||
for (IColumn column : cm.getSortedColumns())
|
||||
addColumn(column, allocator);
|
||||
}
|
||||
|
||||
public boolean replace(IColumn oldColumn, IColumn newColumn)
|
||||
{
|
||||
if (!oldColumn.name().equals(newColumn.name()))
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
return replace(oldColumn.name(), oldColumn, newColumn);
|
||||
}
|
||||
|
||||
public IColumn getColumn(ByteBuffer name)
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
|
||||
public void removeColumn(ByteBuffer name)
|
||||
{
|
||||
remove(name);
|
||||
}
|
||||
|
||||
public Collection<IColumn> getSortedColumns()
|
||||
{
|
||||
return values();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getReverseSortedColumns()
|
||||
{
|
||||
return descendingMap().values();
|
||||
}
|
||||
|
||||
public SortedSet<ByteBuffer> getColumnNames()
|
||||
{
|
||||
return keySet();
|
||||
}
|
||||
|
||||
public int getEstimatedColumnCount()
|
||||
{
|
||||
return size();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator()
|
||||
{
|
||||
return values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator()
|
||||
{
|
||||
return getReverseSortedColumns().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator(ByteBuffer start)
|
||||
{
|
||||
return tailMap(start).values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator(ByteBuffer start)
|
||||
{
|
||||
return descendingMap().tailMap(start).values().iterator();
|
||||
}
|
||||
}
|
||||
|
|
@ -24,11 +24,15 @@ import java.util.SortedMap;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.utils.Allocator;
|
||||
|
||||
public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> implements ISortedColumns
|
||||
public class TreeMapBackedSortedColumns extends AbstractThreadUnsafeSortedColumns implements ISortedColumns
|
||||
{
|
||||
private final TreeMap<ByteBuffer, IColumn> map;
|
||||
|
||||
public static final ISortedColumns.Factory factory = new Factory()
|
||||
{
|
||||
public ISortedColumns create(AbstractType<?> comparator, boolean insertReversed)
|
||||
|
|
@ -49,17 +53,17 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
|
||||
public AbstractType<?> getComparator()
|
||||
{
|
||||
return (AbstractType)comparator();
|
||||
return (AbstractType)map.comparator();
|
||||
}
|
||||
|
||||
private TreeMapBackedSortedColumns(AbstractType<?> comparator)
|
||||
{
|
||||
super(comparator);
|
||||
this.map = new TreeMap<ByteBuffer, IColumn>(comparator);
|
||||
}
|
||||
|
||||
private TreeMapBackedSortedColumns(SortedMap<ByteBuffer, IColumn> columns)
|
||||
{
|
||||
super(columns);
|
||||
this.map = new TreeMap<ByteBuffer, IColumn>(columns);
|
||||
}
|
||||
|
||||
public ISortedColumns.Factory getFactory()
|
||||
|
|
@ -69,7 +73,7 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
|
||||
public ISortedColumns cloneMe()
|
||||
{
|
||||
return new TreeMapBackedSortedColumns(this);
|
||||
return new TreeMapBackedSortedColumns(map);
|
||||
}
|
||||
|
||||
public boolean isInsertReversed()
|
||||
|
|
@ -88,7 +92,7 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
// but TreeMap lacks putAbsent. Rather than split it into a "get, then put" check, we do it as follows,
|
||||
// which saves the extra "get" in the no-conflict case [for both normal and super columns],
|
||||
// in exchange for a re-put in the SuperColumn case.
|
||||
IColumn oldColumn = put(name, column);
|
||||
IColumn oldColumn = map.put(name, column);
|
||||
if (oldColumn != null)
|
||||
{
|
||||
if (oldColumn instanceof SuperColumn)
|
||||
|
|
@ -98,13 +102,13 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
// add the new one to the old, then place old back in the Map, rather than copy the old contents
|
||||
// into the new Map entry.
|
||||
((SuperColumn) oldColumn).putColumn((SuperColumn)column, allocator);
|
||||
put(name, oldColumn);
|
||||
map.put(name, oldColumn);
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate reconciled col from old (existing) col and new col
|
||||
IColumn reconciledColumn = column.reconcile(oldColumn, allocator);
|
||||
put(name, reconciledColumn);
|
||||
map.put(name, reconciledColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,10 +116,10 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
/**
|
||||
* We need to go through each column in the column container and resolve it before adding
|
||||
*/
|
||||
public void addAll(ISortedColumns cm, Allocator allocator)
|
||||
protected void addAllColumns(ISortedColumns cm, Allocator allocator, Function<IColumn, IColumn> transformation)
|
||||
{
|
||||
for (IColumn column : cm.getSortedColumns())
|
||||
addColumn(column, allocator);
|
||||
addColumn(transformation.apply(column), allocator);
|
||||
}
|
||||
|
||||
public boolean replace(IColumn oldColumn, IColumn newColumn)
|
||||
|
|
@ -127,15 +131,15 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
// column or the column was not equal to oldColumn (to be coherent
|
||||
// with other implementation). We optimize for the common case where
|
||||
// oldColumn do is present though.
|
||||
IColumn previous = put(oldColumn.name(), newColumn);
|
||||
IColumn previous = map.put(oldColumn.name(), newColumn);
|
||||
if (previous == null)
|
||||
{
|
||||
remove(oldColumn.name());
|
||||
map.remove(oldColumn.name());
|
||||
return false;
|
||||
}
|
||||
if (!previous.equals(oldColumn))
|
||||
{
|
||||
put(oldColumn.name(), previous);
|
||||
map.put(oldColumn.name(), previous);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -143,37 +147,42 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
|
||||
public IColumn getColumn(ByteBuffer name)
|
||||
{
|
||||
return get(name);
|
||||
return map.get(name);
|
||||
}
|
||||
|
||||
public void removeColumn(ByteBuffer name)
|
||||
{
|
||||
remove(name);
|
||||
map.remove(name);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getSortedColumns()
|
||||
{
|
||||
return values();
|
||||
return map.values();
|
||||
}
|
||||
|
||||
public Collection<IColumn> getReverseSortedColumns()
|
||||
{
|
||||
return descendingMap().values();
|
||||
return map.descendingMap().values();
|
||||
}
|
||||
|
||||
public SortedSet<ByteBuffer> getColumnNames()
|
||||
{
|
||||
return navigableKeySet();
|
||||
}
|
||||
|
||||
public int getEstimatedColumnCount()
|
||||
{
|
||||
return size();
|
||||
return map.navigableKeySet();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> iterator()
|
||||
{
|
||||
return values().iterator();
|
||||
return map.values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator()
|
||||
|
|
@ -183,11 +192,11 @@ public class TreeMapBackedSortedColumns extends TreeMap<ByteBuffer, IColumn> imp
|
|||
|
||||
public Iterator<IColumn> iterator(ByteBuffer start)
|
||||
{
|
||||
return tailMap(start).values().iterator();
|
||||
return map.tailMap(start).values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<IColumn> reverseIterator(ByteBuffer start)
|
||||
{
|
||||
return descendingMap().tailMap(start).values().iterator();
|
||||
return map.descendingMap().tailMap(start).values().iterator();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ import org.junit.Test;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.utils.HeapAllocator;
|
||||
|
|
@ -76,7 +78,7 @@ public class ArrayBackedSortedColumnsTest
|
|||
for (int i = 0; i < values2.length; ++i)
|
||||
map2.addColumn(new Column(ByteBufferUtil.bytes(values2[reversed ? values2.length - 1 - i : i])), HeapAllocator.instance);
|
||||
|
||||
map2.addAll(map, HeapAllocator.instance);
|
||||
map2.addAll(map, HeapAllocator.instance, new Function<IColumn, IColumn>(){ public IColumn apply(IColumn c) { return c; }; });
|
||||
|
||||
Iterator<IColumn> iter = map2.iterator();
|
||||
assertEquals("1st column", 1, iter.next().name().getInt(0));
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ public class ColumnFamilyTest extends SchemaLoader
|
|||
public void testSuperColumnResolution()
|
||||
{
|
||||
testSuperColumnResolution(TreeMapBackedSortedColumns.factory());
|
||||
testSuperColumnResolution(ThreadSafeSortedColumns.factory());
|
||||
testSuperColumnResolution(AtomicSortedColumns.factory());
|
||||
// array-sorted does allow conflict resolution IF it is the last column. Bit of an edge case.
|
||||
testSuperColumnResolution(ArrayBackedSortedColumns.factory());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue