blob: 0f5ca49fbd12e904860449c66246884697de3fa6 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>Apache BookKeeper&trade; - The Advanced Ledger API</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/normalize.css">
<link rel="stylesheet" href="/css/tippy.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="shortcut icon" href="/img/favicon.ico">
<script src="/js/tippy.min.js"></script>
<script type="text/javascript">
var shiftWindow = function() { scrollBy(0, -25); };
window.addEventListener("hashchange", shiftWindow);
window.addEventListener("pageshow", shiftWindow);
function load() { if (window.location.hash) shiftWindow(); }
</script>
</head>
<body class="body">
<main class="main">
<nav class="navbar bk-topnav">
<div class="navbar-brand">
<a class="navbar-item bk-brand" href="/">
Apache BookKeeper&trade;
</a>
<div class="navbar-burger burger" data-target="bkNav">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="bkNav" class="navbar-menu">
<div class="navbar-start">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Documentation</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/docs/latest/overview/overview">
Version 4.15.0-SNAPSHOT
<span class="tag is-warning">Development</span>
</a>
<a class="navbar-item" href="/docs/latest/api/javadoc">
<span class="icon bk-javadoc-icon">
<img src="/img/java-icon.svg">
</span>
Javadoc
</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/docs/4.14.0/overview/overview">
Release 4.14.0
</a>
<a class="navbar-item" href="/docs/4.13.0/overview/overview">
Release 4.13.0
</a>
<a class="navbar-item" href="/docs/4.12.1/overview/overview">
Release 4.12.1
</a>
<a class="navbar-item" href="/docs/4.12.0/overview/overview">
Release 4.12.0
</a>
<a class="navbar-item" href="/docs/4.11.1/overview/overview">
Release 4.11.1
<span class="tag is-success">Stable</span>
</a>
<a class="navbar-item" href="/docs/4.11.0/overview/overview">
Release 4.11.0
</a>
<a class="navbar-item" href="/docs/4.10.0/overview/overview">
Release 4.10.0
</a>
<a class="navbar-item" href="/archives/docs/r4.9.2">
Release 4.9.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.9.1">
Release 4.9.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.9.0">
Release 4.9.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.2">
Release 4.8.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.1">
Release 4.8.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.8.0">
Release 4.8.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.3">
Release 4.7.3
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.2">
Release 4.7.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.1">
Release 4.7.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.7.0">
Release 4.7.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.2">
Release 4.6.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.1">
Release 4.6.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.6.0">
Release 4.6.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.5.1">
Release 4.5.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.5.0">
Release 4.5.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.4.0">
Release 4.4.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.2">
Release 4.3.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.1">
Release 4.3.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.3.0">
Release 4.3.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.4">
Release 4.2.4
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.3">
Release 4.2.3
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.2">
Release 4.2.2
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.1">
Release 4.2.1
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.2.0">
Release 4.2.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.1.0">
Release 4.1.0
<span class="tag is-warning">EOL</span>
</a>
<a class="navbar-item" href="/archives/docs/r4.0.0">
Release 4.0.0
<span class="tag is-warning">EOL</span>
</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Community</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/community/mailing-lists">Mailing lists</a>
<a class="navbar-item" href="/community/slack">Slack</a>
<a class="navbar-item" href="https://github.com/apache/bookkeeper/issues">Github Issues</a>
<a class="navbar-item" href="/community/releases">Release Management</a>
<a class="navbar-item" href="/community/meeting">Community Meetings</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/community/contributing">Contribution Guide</a>
<a class="navbar-item" href="/community/coding_guide">Coding Guide</a>
<a class="navbar-item" href="/community/testing">Testing Guide</a>
<a class="navbar-item" href="/community/issue-report">Issue Report Guide</a>
<a class="navbar-item" href="/community/release_guide">Release Guide</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/community/presentations">Presentations</a>
<a class="navbar-item" href="/community/bookkeeper_proposals">BookKeeper Proposals</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Project</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item" href="/project/who">Who are we?</a>
<a class="navbar-item" href="/project/bylaws">Bylaws</a>
<a class="navbar-item" href="http://www.apache.org/licenses/">License</a>
<hr class="dropdown-divider">
<a class="navbar-item" href="/project/privacy">Privacy policy</a>
<a class="navbar-item" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="navbar-item" href="http://www.apache.org/foundation/thanks.html">Thanks</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="field is-grouped">
<p class="control">
<a class="button bk-twitter" href="https://twitter.com/asfbookkeeper">
<span class="icon">
<i class="fa fa-twitter"></i>
</span>
<span>Twitter</span>
</a>
</p>
<p class="control">
<a class="button" href="https://github.com/apache/bookkeeper">
<span class="icon">
<i class="fa fa-github"></i>
</span>
<span>GitHub</span>
</a>
</p>
<p class="control">
<a class="button is-primary" href="/releases">
<span class="icon">
<i class="fa fa-download"></i>
</span>
<span>Download</span>
</a>
</p>
</div>
</div>
</div>
</div>
</nav>
<div class="bk-docs-container">
<div class="columns is-gapless">
<div class="column is-2 is-hidden-mobile">
<div class="container">
<aside class="sidebar">
<a class="button is-info">
Version: 4.11.1
</a>
<hr />
<p>
Getting started
</p>
<ul class="sidebar-items">
<li>
<a href="../../getting-started/installation">
Installation
</a>
</li>
<li>
<a href="../../getting-started/run-locally">
Run bookies locally
</a>
</li>
<li>
<a href="../../getting-started/concepts">
Concepts and architecture
</a>
</li>
</ul>
<p>
Deployment
</p>
<ul class="sidebar-items">
<li>
<a href="../../deployment/manual">
Manual deployment
</a>
</li>
<li>
<a href="../../deployment/dcos">
BookKeeper on DC/OS
</a>
</li>
<li>
<a href="../../deployment/kubernetes">
BookKeeper on Kubernetes
</a>
</li>
</ul>
<p>
Administration
</p>
<ul class="sidebar-items">
<li>
<a href="../../admin/bookies">
BookKeeper administration
</a>
</li>
<li>
<a href="../../admin/autorecovery">
AutoRecovery
</a>
</li>
<li>
<a href="../../admin/metrics">
Metric collection
</a>
</li>
<li>
<a href="../../admin/upgrade">
Upgrade
</a>
</li>
<li>
<a href="../../admin/http">
BookKeeper Admin REST API
</a>
</li>
<li>
<a href="../../admin/decomission">
Decommissioning Bookies
</a>
</li>
</ul>
<p>
API
</p>
<ul class="sidebar-items">
<li>
<a href="../../api/overview">
Overview
</a>
</li>
<li>
<a href="../../api/ledger-api">
Ledger API
</a>
</li>
<li>
<a href="../../api/ledger-adv-api">
Advanced Ledger API
</a>
</li>
<li>
<a href="../../api/distributedlog-api">
DistributedLog
</a>
</li>
<li>
<a href="../../api/javadoc">
Java API Docs
</a>
</li>
</ul>
<p>
Security
</p>
<ul class="sidebar-items">
<li>
<a href="../../security/overview">
Overview
</a>
</li>
<li>
<a href="../../security/tls">
TLS Authentication
</a>
</li>
<li>
<a href="../../security/sasl">
SASL Authentication
</a>
</li>
<li>
<a href="../../security/zookeeper">
ZooKeeper Authentication
</a>
</li>
</ul>
<p>
Development
</p>
<ul class="sidebar-items">
<li>
<a href="../../development/protocol">
BookKeeper protocol
</a>
</li>
</ul>
<p>
Reference
</p>
<ul class="sidebar-items">
<li>
<a href="../../reference/config">
Configuration
</a>
</li>
<li>
<a href="../../reference/cli">
Command-line tools
</a>
</li>
<li>
<a href="../../reference/metrics">
Metrics
</a>
</li>
</ul>
</aside>
</div>
</div>
<div class="column is-8 bk-docs-block">
<header class="docs-title">
<nav class="level bk-level">
<div class="level-left">
<div class="level-item">
<h1 class="title">The Advanced Ledger API</h1>
</div>
</div>
</nav>
</header>
<hr />
<div class="content">
<section class="bk-main-content">
<p>In release <code class="highlighter-rouge">4.5.0</code>, Apache BookKeeper introduces a few advanced API for advanced usage.
This sections covers these advanced APIs.</p>
<blockquote>
<p>Before learn the advanced API, please read <a href="../ledger-api">Ledger API</a> first.</p>
</blockquote>
<h2 id="ledgerhandleadv">LedgerHandleAdv</h2>
<p><a href="../javadoc/org/apache/bookkeeper/client/LedgerHandleAdv"><code class="highlighter-rouge">LedgerHandleAdv</code></a> is an advanced extension of <a href="../javadoc/org/apache/bookkeeper/client/LedgerHandle"><code class="highlighter-rouge">LedgerHandle</code></a>.
It allows user passing in an <code class="highlighter-rouge">entryId</code> when adding an entry.</p>
<h3 id="creating-advanced-ledgers">Creating advanced ledgers</h3>
<p>Here’s an exmaple:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">byte</span><span class="o">[]</span> <span class="n">passwd</span> <span class="o">=</span> <span class="s">"some-passwd"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">();</span>
<span class="nc">LedgerHandleAdv</span> <span class="n">handle</span> <span class="o">=</span> <span class="n">bkClient</span><span class="o">.</span><span class="na">createLedgerAdv</span><span class="o">(</span>
<span class="mi">3</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="c1">// replica settings</span>
<span class="nc">DigestType</span><span class="o">.</span><span class="na">CRC32</span><span class="o">,</span>
<span class="n">passwd</span><span class="o">);</span>
</code></pre></div></div>
<p>You can also create advanced ledgers asynchronously.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">LedgerCreationCallback</span> <span class="kd">implements</span> <span class="nc">AsyncCallback</span><span class="o">.</span><span class="na">CreateCallback</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">createComplete</span><span class="o">(</span><span class="kt">int</span> <span class="n">returnCode</span><span class="o">,</span> <span class="nc">LedgerHandle</span> <span class="n">handle</span><span class="o">,</span> <span class="nc">Object</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Ledger successfully created"</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">client</span><span class="o">.</span><span class="na">asyncCreateLedgerAdv</span><span class="o">(</span>
<span class="mi">3</span><span class="o">,</span> <span class="c1">// ensemble size</span>
<span class="mi">3</span><span class="o">,</span> <span class="c1">// write quorum size</span>
<span class="mi">2</span><span class="o">,</span> <span class="c1">// ack quorum size</span>
<span class="nc">BookKeeper</span><span class="o">.</span><span class="na">DigestType</span><span class="o">.</span><span class="na">CRC32</span><span class="o">,</span>
<span class="n">password</span><span class="o">,</span>
<span class="k">new</span> <span class="nf">LedgerCreationCallback</span><span class="o">(),</span>
<span class="s">"some context"</span>
<span class="o">);</span>
</code></pre></div></div>
<p>Besides the APIs above, BookKeeper allows users providing <code class="highlighter-rouge">ledger-id</code> when creating advanced ledgers.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">long</span> <span class="n">ledgerId</span> <span class="o">=</span> <span class="o">...;</span> <span class="c1">// the ledger id is generated externally.</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">passwd</span> <span class="o">=</span> <span class="s">"some-passwd"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">();</span>
<span class="nc">LedgerHandleAdv</span> <span class="n">handle</span> <span class="o">=</span> <span class="n">bkClient</span><span class="o">.</span><span class="na">createLedgerAdv</span><span class="o">(</span>
<span class="n">ledgerId</span><span class="o">,</span> <span class="c1">// ledger id generated externally</span>
<span class="mi">3</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="c1">// replica settings</span>
<span class="nc">DigestType</span><span class="o">.</span><span class="na">CRC32</span><span class="o">,</span>
<span class="n">passwd</span><span class="o">);</span>
</code></pre></div></div>
<blockquote>
<p>Please note, it is users’ responsibility to provide a unique ledger id when using the API above.
If a ledger already exists when users try to create an advanced ledger with same ledger id,
a <a href="../javadoc/org/apache/bookkeeper/client/BKException.BKLedgerExistException.html">LedgerExistsException</a> is thrown by the bookkeeper client.</p>
</blockquote>
<p>Creating advanced ledgers can be done throught a fluent API since 4.6.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">BookKeeper</span> <span class="n">bk</span> <span class="o">=</span> <span class="o">...;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">passwd</span> <span class="o">=</span> <span class="s">"some-passwd"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">();</span>
<span class="nc">WriteHandle</span> <span class="n">wh</span> <span class="o">=</span> <span class="n">bk</span><span class="o">.</span><span class="na">newCreateLedgerOp</span><span class="o">()</span>
<span class="o">.</span><span class="na">withDigestType</span><span class="o">(</span><span class="nc">DigestType</span><span class="o">.</span><span class="na">CRC32</span><span class="o">)</span>
<span class="o">.</span><span class="na">withPassword</span><span class="o">(</span><span class="n">passwd</span><span class="o">)</span>
<span class="o">.</span><span class="na">withEnsembleSize</span><span class="o">(</span><span class="mi">3</span><span class="o">)</span>
<span class="o">.</span><span class="na">withWriteQuorumSize</span><span class="o">(</span><span class="mi">3</span><span class="o">)</span>
<span class="o">.</span><span class="na">withAckQuorumSize</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span>
<span class="o">.</span><span class="na">makeAdv</span><span class="o">()</span> <span class="c1">// convert the create ledger builder to create ledger adv builder</span>
<span class="o">.</span><span class="na">withLedgerId</span><span class="o">(</span><span class="mi">1234L</span><span class="o">)</span>
<span class="o">.</span><span class="na">execute</span><span class="o">()</span> <span class="c1">// execute the creation op</span>
<span class="o">.</span><span class="na">get</span><span class="o">();</span> <span class="c1">// wait for the execution to complete</span>
</code></pre></div></div>
<h3 id="add-entries">Add Entries</h3>
<p>The normal <a href="ledger-api/#adding-entries-to-ledgers">add entries api</a> in advanced ledgers are disabled. Instead, when users want to add entries
to advanced ledgers, an entry id is required to pass in along with the entry data when adding an entry.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">long</span> <span class="n">entryId</span> <span class="o">=</span> <span class="o">...;</span> <span class="c1">// entry id generated externally</span>
<span class="n">ledger</span><span class="o">.</span><span class="na">addEntry</span><span class="o">(</span><span class="n">entryId</span><span class="o">,</span> <span class="s">"Some entry data"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">());</span>
</code></pre></div></div>
<p>If you are using the new API, you can do as following:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">WriteHandle</span> <span class="n">wh</span> <span class="o">=</span> <span class="o">...;</span>
<span class="kt">long</span> <span class="n">entryId</span> <span class="o">=</span> <span class="o">...;</span> <span class="c1">// entry id generated externally</span>
<span class="n">wh</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">entryId</span><span class="o">,</span> <span class="s">"Some entry data"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">()).</span><span class="na">get</span><span class="o">();</span>
</code></pre></div></div>
<p>A few notes when using this API:</p>
<ul>
<li>The entry id has to be non-negative.</li>
<li>Clients are okay to add entries out of order.</li>
<li>However, the entries are only acknowledged in a monotonic order starting from 0.</li>
</ul>
<h3 id="read-entries">Read Entries</h3>
<p>The read entries api in advanced ledgers remain same as <a href="../ledger-api/#reading-entries-from-ledgers">normal ledgers</a>.</p>
</section>
</div>
</div>
<div class="column is-2 is-hidden-mobile">
<div class="toc">
<h2 class="title">The Advanced Ledger API</h2>
<ul class="section-nav">
<li class="toc-entry toc-h2"><a href="#ledgerhandleadv">LedgerHandleAdv</a>
<ul>
<li class="toc-entry toc-h3"><a href="#creating-advanced-ledgers">Creating advanced ledgers</a></li>
<li class="toc-entry toc-h3"><a href="#add-entries">Add Entries</a></li>
<li class="toc-entry toc-h3"><a href="#read-entries">Read Entries</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="entry-popover-html" class="popover-template">
<p>An entry is a sequence of bytes (plus some metadata) written to a BookKeeper ledger. Entries are also known as records.</p>
</div>
<div id="ledger-popover-html" class="popover-template">
<p>A ledger is a sequence of entries written to BookKeeper. Entries are written sequentially to ledgers and at most once, giving ledgers append-only semantics.</p>
</div>
<div id="bookie-popover-html" class="popover-template">
<p>A bookie is an individual BookKeeper storage server.</p>
<p>Bookies store the content of ledgers and act as a distributed ensemble.</p>
</div>
<div id="rereplication-popover-html" class="popover-template">
<p>A subsystem that runs in the background on bookies to ensure that ledgers are fully replicated even if one bookie from the ensemble is down.</p>
</div>
<div id="striping-popover-html" class="popover-template">
<p>Striping is the process of distributing BookKeeper ledgers to sub-groups of bookies rather than to all bookies in a BookKeeper ensemble.</p>
<p>Striping is essential to ensuring fast performance.</p>
</div>
<div id="striped-popover-html" class="popover-template">
<p>Striping is the process of distributing BookKeeper ledgers to sub-groups of bookies rather than to all bookies in a BookKeeper ensemble.</p>
<p>Striping is essential to ensuring fast performance.</p>
</div>
<div id="journal-popover-html" class="popover-template">
<p>A journal file stores BookKeeper transaction logs.</p>
</div>
<div id="fencing-popover-html" class="popover-template">
<p>When a reader forces a ledger to close, preventing any further entries from being written to the ledger.</p>
</div>
<div id="record-popover-html" class="popover-template">
<p>A record is a sequence of bytes (plus some metadata) written to a BookKeeper ledger. Records are also known as entries.</p>
</div>
<script type="text/javascript">
tippy('#entry-popover', {
html: '#entry-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#ledger-popover', {
html: '#ledger-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#bookie-popover', {
html: '#bookie-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#rereplication-popover', {
html: '#rereplication-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#striping-popover', {
html: '#striping-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#striped-popover', {
html: '#striped-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#journal-popover', {
html: '#journal-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#fencing-popover', {
html: '#fencing-popover-html',
arrow: true,
animation: 'fade'
});
tippy('#record-popover', {
html: '#record-popover-html',
arrow: true,
animation: 'fade'
});
</script>
</main>
<footer class="footer">
<div class="container">
<div class="content has-text-centered">
<p>
Copyright &copy; 2016 - 2021 <a href="https://www.apache.org/">The Apache Software Foundation</a>,<br /> licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, version 2.0</a>.
</p>
<p>
Apache BookKeeper, BookKeeper®, Apache®, the Apache feature logo, and the Apache BookKeeper logo are either registered trademarks or trademarks of The Apache Software Foundation.
</p>
</div>
</div>
</footer>
</body>
<script src="/js/app.js"></script>
<!--
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.
-->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-104419626-1', 'auto');
ga('send', 'pageview');
</script>
</html>