blob: 18f00f11cb52aca6a77a24f029c6cebdc22b7f21 [file] [log] [blame]
<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-4.9.2 plugin-docs plugin-id-default docs-doc-id-api/ledger-api">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v2.4.0">
<title data-rh="true">The Ledger API | Apache BookKeeper</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://bookkeeper.apache.org/docs/4.9.2/api/ledger-api"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="4.9.2"><meta data-rh="true" name="docusaurus_tag" content="docs-default-4.9.2"><meta data-rh="true" name="docsearch:version" content="4.9.2"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-4.9.2"><meta data-rh="true" property="og:title" content="The Ledger API | Apache BookKeeper"><meta data-rh="true" name="description" content="The ledger API is a lower-level API for BookKeeper that enables you to interact with ledgers directly."><meta data-rh="true" property="og:description" content="The ledger API is a lower-level API for BookKeeper that enables you to interact with ledgers directly."><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://bookkeeper.apache.org/docs/4.9.2/api/ledger-api"><link data-rh="true" rel="alternate" href="https://bookkeeper.apache.org/docs/4.9.2/api/ledger-api" hreflang="en"><link data-rh="true" rel="alternate" href="https://bookkeeper.apache.org/docs/4.9.2/api/ledger-api" hreflang="x-default"><link rel="stylesheet" href="/assets/css/styles.49914aab.css">
<link rel="preload" href="/assets/js/runtime~main.435d5f64.js" as="script">
<link rel="preload" href="/assets/js/main.0f234beb.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/img/bk-logo.svg" alt="Apache Bookkeeper" class="themedImage_ToTc themedImage--light_HNdA"><img src="/img/bk-logo.svg" alt="Apache Bookkeeper" class="themedImage_ToTc themedImage--dark_i4oU"></div><b class="navbar__title text--truncate">Apache BookKeeper</b></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/4.9.2/overview/">Documentation</a><div class="navbar__item dropdown dropdown--hoverable"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link">Community</a><ul class="dropdown__menu"><li><a class="dropdown__link" href="/community/mailing-lists">Mailing lists</a></li><li><a class="dropdown__link" href="/community/slack">Slack</a></li><li><a href="https://github.com/apache/bookkeeper/issues" target="_blank" rel="noopener noreferrer" class="dropdown__link">Github issues<svg width="12" height="12" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li><a class="dropdown__link" href="/community/releases">Release management</a></li><li><a class="dropdown__link" href="/community/meeting">Community meetings</a></li><li><a class="dropdown__link" href="/community/contributing">Contribution guide</a></li><li><a class="dropdown__link" href="/community/coding-guide">Coding guide</a></li><li><a class="dropdown__link" href="/community/testing">Testing guide</a></li><li><a class="dropdown__link" href="/community/issue-report">Issue report guide</a></li><li><a class="dropdown__link" href="/community/release-guide">Release guide</a></li><li><a class="dropdown__link" href="/community/presentations">Presentations</a></li><li><a class="dropdown__link" href="/community/bookkeeper-proposals">BookKeeper proposals (BP)</a></li></ul></div><div class="navbar__item dropdown dropdown--hoverable"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link">Project</a><ul class="dropdown__menu"><li><a class="dropdown__link" href="/project/who">Who are we?</a></li><li><a class="dropdown__link" href="/project/bylaws">Bylaws</a></li><li><a href="https://apache.org/licenses" target="_blank" rel="noopener noreferrer" class="dropdown__link">License<svg width="12" height="12" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li><a class="dropdown__link" href="/project/privacy">Privacy policy</a></li><li><a href="https://www.apache.org/foundation/sponsorship.html" target="_blank" rel="noopener noreferrer" class="dropdown__link">Sponsorship<svg width="12" height="12" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li><a href="https://www.apache.org/foundation/thanks.html" target="_blank" rel="noopener noreferrer" class="dropdown__link">Thanks<svg width="12" height="12" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div><div class="navbar__items navbar__items--right"><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a class="navbar__link" aria-haspopup="true" aria-expanded="false" role="button" href="/docs/4.9.2/overview/">4.9.2</a><ul class="dropdown__menu"><li><a class="dropdown__link" href="/docs/next/api/ledger-api">Next</a></li><li><a class="dropdown__link" href="/docs/api/ledger-api">4.16.4</a></li><li><a class="dropdown__link" href="/docs/4.15.5/api/ledger-api">4.15.5</a></li><li><a class="dropdown__link" href="/docs/4.14.8/api/ledger-api">4.14.8</a></li><li><a class="dropdown__link" href="/docs/4.13.0/api/ledger-api">4.13.0</a></li><li><a class="dropdown__link" href="/docs/4.12.1/api/ledger-api">4.12.1</a></li><li><a class="dropdown__link" href="/docs/4.11.1/api/ledger-api">4.11.1</a></li><li><a class="dropdown__link" href="/docs/4.10.0/api/ledger-api">4.10.0</a></li><li><a aria-current="page" class="dropdown__link dropdown__link--active" href="/docs/4.9.2/api/ledger-api">4.9.2</a></li><li><a class="dropdown__link" href="/docs/4.8.2/api/ledger-api">4.8.2</a></li><li><a class="dropdown__link" href="/docs/4.7.3/api/ledger-api">4.7.3</a></li><li><a class="dropdown__link" href="/docs/4.6.2/api/ledger-api">4.6.2</a></li><li><a class="dropdown__link" href="/docs/4.5.1/api/ledger-api">4.5.1</a></li></ul></div><a class="navbar__item navbar__link" href="/releases">Download</a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live="polite"><svg viewBox="0 0 24 24" width="24" height="24" class="lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" class="darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg></button></div><div class="searchBox_ZlJk"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0 docsWrapper_BCFX"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docPage__5DB"><aside class="theme-doc-sidebar-container docSidebarContainer_b6E3"><div class="sidebarViewport_Xe31"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/docs/4.9.2/overview/">Overview</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/getting-started/installation">Getting started</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/deployment/manual">Deployment</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/admin/bookies">Administration</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" aria-expanded="true" href="/docs/4.9.2/api/overview">API</a></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/4.9.2/api/overview">Overview</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/docs/4.9.2/api/ledger-api">Ledger API</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/4.9.2/api/ledger-adv-api">Advanced Ledger API</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/4.9.2/api/distributedlog-api">DistributedLog</a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/security/overview">Security</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/development/protocol">Development</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/docs/4.9.2/reference/config">Reference</a></div></li></ul></nav></div></div></aside><main class="docMainContainer_gTbr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><span class="theme-doc-version-badge badge badge--secondary">Version: 4.9.2</span><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>The Ledger API</h1></header><p>The ledger API is a lower-level API for BookKeeper that enables you to interact with ledgers directly.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-java-ledger-api-client">The Java ledger API client<a href="#the-java-ledger-api-client" class="hash-link" aria-label="Direct link to The Java ledger API client" title="Direct link to The Java ledger API client"></a></h2><p>To get started with the Java client for BookKeeper, install the <code>bookkeeper-server</code> library as a dependency in your Java application.</p><blockquote><p>For a more in-depth tutorial that involves a real use case for BookKeeper, see the <a href="#example-application">Example application</a> guide.</p></blockquote><h2 class="anchor anchorWithStickyNavbar_LWe7" id="installation">Installation<a href="#installation" class="hash-link" aria-label="Direct link to Installation" title="Direct link to Installation"></a></h2><p>The BookKeeper Java client library is available via <a href="http://search.maven.org/" target="_blank" rel="noopener noreferrer">Maven Central</a> and can be installed using <a href="#maven">Maven</a>, <a href="#gradle">Gradle</a>, and other build tools.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="maven">Maven<a href="#maven" class="hash-link" aria-label="Direct link to Maven" title="Direct link to Maven"></a></h3><p>If you&#x27;re using <a href="https://maven.apache.org/" target="_blank" rel="noopener noreferrer">Maven</a>, add this to your <a href="https://maven.apache.org/guides/introduction/introduction-to-the-pom.html" target="_blank" rel="noopener noreferrer"><code>pom.xml</code></a> build configuration file:</p><div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- in your &lt;properties&gt; block --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">bookkeeper.version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">4.9.2</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">bookkeeper.version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- in your &lt;dependencies&gt; block --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">dependency</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">groupId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">org.apache.bookkeeper</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">groupId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">artifactId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">bookkeeper-server</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">artifactId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">${bookkeeper.version}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">dependency</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>BookKeeper uses google <a href="https://github.com/google/protobuf/tree/master/java" target="_blank" rel="noopener noreferrer">protobuf</a> and <a href="https://github.com/google/guava" target="_blank" rel="noopener noreferrer">guava</a> libraries
a lot. If your application might include different versions of protobuf or guava introduced by other dependencies, you can choose to use the
shaded library, which relocate classes of protobuf and guava into a different namespace to avoid conflicts.</p><div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- in your &lt;properties&gt; block --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">bookkeeper.version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">4.9.2</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">bookkeeper.version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- in your &lt;dependencies&gt; block --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">dependency</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">groupId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">org.apache.bookkeeper</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">groupId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">artifactId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">bookkeeper-server-shaded</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">artifactId</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">${bookkeeper.version}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">version</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">dependency</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="gradle">Gradle<a href="#gradle" class="hash-link" aria-label="Direct link to Gradle" title="Direct link to Gradle"></a></h3><p>If you&#x27;re using <a href="https://gradle.org/" target="_blank" rel="noopener noreferrer">Gradle</a>, add this to your <a href="https://spring.io/guides/gs/gradle/" target="_blank" rel="noopener noreferrer"><code>build.gradle</code></a> build configuration file:</p><div class="language-groovy codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-groovy codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">dependencies {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> compile group: &#x27;org.apache.bookkeeper&#x27;, name: &#x27;bookkeeper-server&#x27;, version: &#x27;4.9.2&#x27;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Alternatively:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dependencies {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> compile &#x27;org.apache.bookkeeper:bookkeeper-server:4.9.2&#x27;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Similarly as using maven, you can also configure to use the shaded jars.</p><div class="language-groovy codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-groovy codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// use the `bookkeeper-server-shaded` jar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">dependencies {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> compile &#x27;org.apache.bookkeeper:bookkeeper-server-shaded:{{ site.latest-version }}&#x27;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="connection-string">Connection string<a href="#connection-string" class="hash-link" aria-label="Direct link to Connection string" title="Direct link to Connection string"></a></h2><p>When interacting with BookKeeper using the Java client, you need to provide your client with a connection string, for which you have three options:</p><ul><li>Provide your entire ZooKeeper connection string, for example <code>zk1:2181,zk2:2181,zk3:2181</code>.</li><li>Provide a host and port for one node in your ZooKeeper cluster, for example <code>zk1:2181</code>. In general, it&#x27;s better to provide a full connection string (in case the ZooKeeper node you attempt to connect to is down).</li><li>If your ZooKeeper cluster can be discovered via DNS, you can provide the DNS name, for example <code>my-zookeeper-cluster.com</code>.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="creating-a-new-client">Creating a new client<a href="#creating-a-new-client" class="hash-link" aria-label="Direct link to Creating a new client" title="Direct link to Creating a new client"></a></h2><p>In order to create a new <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/BookKeeper" target="_blank" rel="noopener noreferrer"><code>BookKeeper</code></a> client object, you need to pass in a <a href="#connection-string">connection string</a>. Here is an example client object using a ZooKeeper connection string:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">try {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> String connectionString = &quot;127.0.0.1:2181&quot;; // For a single-node, local ZooKeeper cluster</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> BookKeeper bkClient = new BookKeeper(connectionString);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">} catch (InterruptedException | IOException | KeeperException e) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> e.printStackTrace();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><blockquote><p>If you&#x27;re running BookKeeper <a href="/docs/4.9.2/getting-started/run-locally">locally</a>, using the <a href="/docs/4.9.2/reference/cli#bookkeeper-localbookie"><code>localbookie</code></a> command, use <code>&quot;127.0.0.1:2181&quot;</code> for your connection string, as in the example above.</p></blockquote><p>There are, however, other ways that you can create a client object:</p><ul><li><p>By passing in a <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/conf/ClientConfiguration" target="_blank" rel="noopener noreferrer"><code>ClientConfiguration</code></a> object. Here&#x27;s an example:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClientConfiguration config = new ClientConfiguration();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">config.setZkServers(zkConnectionString);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">config.setAddEntryTimeout(2000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bkClient = new BookKeeper(config);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>By specifying a <code>ClientConfiguration</code> and a <a href="http://zookeeper.apache.org/doc/current/api/org/apache/zookeeper/ZooKeeper.html" target="_blank" rel="noopener noreferrer"><code>ZooKeeper</code></a> client object:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ClientConfiguration config = new ClientConfiguration();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">config.setAddEntryTimeout(5000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ZooKeeper zkClient = new ZooKeeper(/* client args */);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bkClient = new BookKeeper(config, zkClient);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li><li><p>Using the <code>forConfig</code> method:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bkClient = BookKeeper.forConfig(conf).build();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="creating-ledgers">Creating ledgers<a href="#creating-ledgers" class="hash-link" aria-label="Direct link to Creating ledgers" title="Direct link to Creating ledgers"></a></h2><p>The easiest way to create a ledger using the Java client is via the <code>createLedger</code> method, which creates a new ledger synchronously and returns a <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/LedgerHandle" target="_blank" rel="noopener noreferrer"><code>LedgerHandle</code></a>. You must specify at least a <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/BookKeeper.DigestType" target="_blank" rel="noopener noreferrer"><code>DigestType</code></a> and a password.</p><p>Here&#x27;s an example:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">byte[] password = &quot;some-password&quot;.getBytes();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">LedgerHandle handle = bkClient.createLedger(BookKeeper.DigestType.MAC, password);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You can also create ledgers asynchronously</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-ledgers-asynchronously">Create ledgers asynchronously<a href="#create-ledgers-asynchronously" class="hash-link" aria-label="Direct link to Create ledgers asynchronously" title="Direct link to Create ledgers asynchronously"></a></h3><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">class LedgerCreationCallback implements AsyncCallback.CreateCallback {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void createComplete(int returnCode, LedgerHandle handle, Object ctx) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Ledger successfully created&quot;);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">client.asyncCreateLedger(</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 3,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 2,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> BookKeeper.DigestType.MAC,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> password,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> new LedgerCreationCallback(),</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> &quot;some context&quot;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="adding-entries-to-ledgers">Adding entries to ledgers<a href="#adding-entries-to-ledgers" class="hash-link" aria-label="Direct link to Adding entries to ledgers" title="Direct link to Adding entries to ledgers"></a></h2><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">long entryId = ledger.addEntry(&quot;Some entry data&quot;.getBytes());</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="add-entries-asynchronously">Add entries asynchronously<a href="#add-entries-asynchronously" class="hash-link" aria-label="Direct link to Add entries asynchronously" title="Direct link to Add entries asynchronously"></a></h3><h2 class="anchor anchorWithStickyNavbar_LWe7" id="reading-entries-from-ledgers">Reading entries from ledgers<a href="#reading-entries-from-ledgers" class="hash-link" aria-label="Direct link to Reading entries from ledgers" title="Direct link to Reading entries from ledgers"></a></h2><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Enumerator&lt;LedgerEntry&gt; entries = handle.readEntries(1, 99);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>To read all possible entries from the ledger:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Enumerator&lt;LedgerEntry&gt; entries =</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> handle.readEntries(0, handle.getLastAddConfirmed());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">while (entries.hasNextElement()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> LedgerEntry entry = entries.nextElement();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Successfully read entry &quot; + entry.getId());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="reading-entries-after-the-lastaddconfirmed-range">Reading entries after the LastAddConfirmed range<a href="#reading-entries-after-the-lastaddconfirmed-range" class="hash-link" aria-label="Direct link to Reading entries after the LastAddConfirmed range" title="Direct link to Reading entries after the LastAddConfirmed range"></a></h3><p><code>readUnconfirmedEntries</code> allowing to read after the LastAddConfirmed range.
It lets the client read without checking the local value of LastAddConfirmed, so that it is possible to read entries for which the writer has not received the acknowledge yet.
For entries which are within the range 0..LastAddConfirmed, BookKeeper guarantees that the writer has successfully received the acknowledge.
For entries outside that range it is possible that the writer never received the acknowledge and so there is the risk that the reader is seeing entries before the writer and this could result in a consistency issue in some cases.
With this method you can even read entries before the LastAddConfirmed and entries after it with one call, the expected consistency will be as described above.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Enumerator&lt;LedgerEntry&gt; entries =</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> handle.readUnconfirmedEntries(0, lastEntryIdExpectedToRead);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">while (entries.hasNextElement()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> LedgerEntry entry = entries.nextElement();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Successfully read entry &quot; + entry.getId());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="deleting-ledgers">Deleting ledgers<a href="#deleting-ledgers" class="hash-link" aria-label="Direct link to Deleting ledgers" title="Direct link to Deleting ledgers"></a></h2><p>Ledgers can be deleted synchronously which may throw exception:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = 1234;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">try {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> bkClient.deleteLedger(ledgerId);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">} catch (Exception e) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> e.printStackTrace();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="delete-entries-asynchronously">Delete entries asynchronously<a href="#delete-entries-asynchronously" class="hash-link" aria-label="Direct link to Delete entries asynchronously" title="Direct link to Delete entries asynchronously"></a></h3><p>Ledgers can also be deleted asynchronously:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">class DeleteEntryCallback implements AsyncCallback.DeleteCallback {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void deleteComplete() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Delete completed&quot;);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bkClient.asyncDeleteLedger(ledgerID, new DeleteEntryCallback(), null);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="simple-example">Simple example<a href="#simple-example" class="hash-link" aria-label="Direct link to Simple example" title="Direct link to Simple example"></a></h2><blockquote><p>For a more involved BookKeeper client example, see the <a href="#example-application">example application</a> below.</p></blockquote><p>In the code sample below, a BookKeeper client:</p><ul><li>creates a ledger</li><li>writes entries to the ledger</li><li>closes the ledger (meaning no further writes are possible)</li><li>re-opens the ledger for reading</li><li>reads all available entries</li></ul><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// Create a client object for the local ensemble. This</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// operation throws multiple exceptions, so make sure to</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// use a try/catch block when instantiating client objects.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bkc = new BookKeeper(&quot;localhost:2181&quot;);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// A password for the new ledger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">byte[] ledgerPassword = /* some sequence of bytes, perhaps random */;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Create a new ledger and fetch its identifier</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">LedgerHandle lh = bkc.createLedger(BookKeeper.DigestType.MAC, ledgerPassword);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = lh.getId();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Create a buffer for four-byte entries</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ByteBuffer entry = ByteBuffer.allocate(4);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">int numberOfEntries = 100;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Add entries to the ledger, then close it</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">for (int i = 0; i &lt; numberOfEntries; i++){</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> entry.putInt(i);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> entry.position(0);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> lh.addEntry(entry.array());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lh.close();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Open the ledger for reading</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lh = bkc.openLedger(ledgerId, BookKeeper.DigestType.MAC, ledgerPassword);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Read all available entries</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Enumeration&lt;LedgerEntry&gt; entries = lh.readEntries(0, numberOfEntries - 1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">while(entries.hasMoreElements()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ByteBuffer result = ByteBuffer.wrap(entries.nextElement().getEntry());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Integer retrEntry = result.getInt();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // Print the integer stored in each entry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(String.format(&quot;Result: %s&quot;, retrEntry));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Close the ledger and the client</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lh.close();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bkc.close();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Running this should return this output:</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Result: </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Result: </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Result: </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># etc</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="example-application">Example application<a href="#example-application" class="hash-link" aria-label="Direct link to Example application" title="Direct link to Example application"></a></h2><p>This tutorial walks you through building an example application that uses BookKeeper as the replicated log. The application uses the BookKeeper Java client to interact with BookKeeper.</p><blockquote><p>The code for this tutorial can be found in <a href="https://github.com/ivankelly/bookkeeper-tutorial/" target="_blank" rel="noopener noreferrer">this GitHub repo</a>. The final code for the <code>Dice</code> class can be found <a href="https://github.com/ivankelly/bookkeeper-tutorial/blob/master/src/main/java/org/apache/bookkeeper/Dice.java" target="_blank" rel="noopener noreferrer">here</a>.</p></blockquote><h3 class="anchor anchorWithStickyNavbar_LWe7" id="setup">Setup<a href="#setup" class="hash-link" aria-label="Direct link to Setup" title="Direct link to Setup"></a></h3><p>Before you start, you will need to have a BookKeeper cluster running locally on your machine. For installation instructions, see <a href="/docs/4.9.2/getting-started/installation">Installation</a>.</p><p>To start up a cluster consisting of six bookies locally:</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ bookkeeper-server/bin/bookkeeper localbookie </span><span class="token number" style="color:#36acaa">6</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You can specify a different number of bookies if you&#x27;d like.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="goal">Goal<a href="#goal" class="hash-link" aria-label="Direct link to Goal" title="Direct link to Goal"></a></h3><p>The goal of the dice application is to have</p><ul><li>multiple instances of this application,</li><li>possibly running on different machines,</li><li>all of which display the exact same sequence of numbers.</li></ul><p>In other words, the log needs to be both durable and consistent, regardless of how many bookies are participating in the BookKeeper ensemble. If one of the bookies crashes or becomes unable to communicate with the other bookies in any way, it should <em>still</em> display the same sequence of numbers as the others. This tutorial will show you how to achieve this.</p><p>To begin, download the base application, compile and run it.</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> clone https://github.com/ivankelly/bookkeeper-tutorial.git</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ mvn package</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ mvn exec:java -Dexec.mainClass</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">org.apache.bookkeeper.Dice</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>That should yield output that looks something like this:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] Scanning for projects...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] ------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] Building tutorial 1.0-SNAPSHOT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] ------------------------------------------------------------------------</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ tutorial ---</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value = 4</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value = 5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value = 3</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-base-application">The base application<a href="#the-base-application" class="hash-link" aria-label="Direct link to The base application" title="Direct link to The base application"></a></h3><p>The application in this tutorial is a dice application. The <code>Dice</code> class below has a <code>playDice</code> function that generates a random number between 1 and 6 every second, prints the value of the dice roll, and runs indefinitely.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class Dice {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Random r = new Random();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> void playDice() throws InterruptedException {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> while (true) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Thread.sleep(1000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Value = &quot; + (r.nextInt(6) + 1));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>When you run the <code>main</code> function of this class, a new <code>Dice</code> object will be instantiated and then run indefinitely:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class Dice {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // other methods</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public static void main(String[] args) throws InterruptedException {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Dice d = new Dice();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> d.playDice();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="leaders-and-followers-and-a-bit-of-background">Leaders and followers (and a bit of background)<a href="#leaders-and-followers-and-a-bit-of-background" class="hash-link" aria-label="Direct link to Leaders and followers (and a bit of background)" title="Direct link to Leaders and followers (and a bit of background)"></a></h3><p>To achieve this common view in multiple instances of the program, we need each instance to agree on what the next number in the sequence will be. For example, the instances must agree that 4 is the first number and 2 is the second number and 5 is the third number and so on. This is a difficult problem, especially in the case that any instance may go away at any time, and messages between the instances can be lost or reordered.</p><p>Luckily, there are already algorithms to solve this. Paxos is an abstract algorithm to implement this kind of agreement, while Zab and Raft are more practical protocols. This video gives a good overview about how these algorithms usually look. They all have a similar core.</p><p>It would be possible to run the Paxos to agree on each number in the sequence. However, running Paxos each time can be expensive. What Zab and Raft do is that they use a Paxos-like algorithm to elect a leader. The leader then decides what the sequence of events should be, putting them in a log, which the other instances can then follow to maintain the same state as the leader.</p><p>Bookkeeper provides the functionality for the second part of the protocol, allowing a leader to write events to a log and have multiple followers tailing the log. However, bookkeeper does not do leader election. You will need a zookeeper or raft instance for that purpose.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-not-just-use-zookeeper">Why not just use ZooKeeper?<a href="#why-not-just-use-zookeeper" class="hash-link" aria-label="Direct link to Why not just use ZooKeeper?" title="Direct link to Why not just use ZooKeeper?"></a></h3><p>There are a number of reasons:</p><ol><li>Zookeeper&#x27;s log is only exposed through a tree like interface. It can be hard to shoehorn your application into this.</li><li>A zookeeper ensemble of multiple machines is limited to one log. You may want one log per resource, which will become expensive very quickly.</li><li>Adding extra machines to a zookeeper ensemble does not increase capacity nor throughput.</li></ol><p>Bookkeeper can be seen as a means of exposing ZooKeeper&#x27;s replicated log to applications in a scalable fashion. ZooKeeper is still used by BookKeeper, however, to maintain consistency guarantees, though clients don&#x27;t need to interact with ZooKeeper directly.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="electing-a-leader">Electing a leader<a href="#electing-a-leader" class="hash-link" aria-label="Direct link to Electing a leader" title="Direct link to Electing a leader"></a></h3><p>We&#x27;ll use zookeeper to elect a leader. A zookeeper instance will have started locally when you started the localbookie application above. To verify it&#x27;s running, run the following command.</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token builtin class-name">echo</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">stat</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">nc</span><span class="token plain"> localhost </span><span class="token number" style="color:#36acaa">2181</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Zookeeper version: </span><span class="token number" style="color:#36acaa">3.4</span><span class="token plain">.6-1569965, built on 02/20/2014 09:09 GMT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Clients:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:59343</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">40</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">41</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:49354</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">11</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">11</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:49361</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:59344</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">38</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">39</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:59345</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">38</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">39</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> /127.0.0.1:59346</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">queued</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">,recved</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">38</span><span class="token plain">,sent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">39</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Latency min/avg/max: </span><span class="token number" style="color:#36acaa">0</span><span class="token plain">/0/23</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Received: </span><span class="token number" style="color:#36acaa">167</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Sent: </span><span class="token number" style="color:#36acaa">170</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Connections: </span><span class="token number" style="color:#36acaa">6</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Outstanding: </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Zxid: 0x11</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Mode: standalone</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Node count: </span><span class="token number" style="color:#36acaa">16</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>To interact with zookeeper, we&#x27;ll use the Curator client rather than the stock zookeeper client. Getting things right with the zookeeper client can be tricky, and curator removes a lot of the pointy corners for you. In fact, curator even provides a leader election recipe, so we need to do very little work to get leader election in our application.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">public class Dice extends LeaderSelectorListenerAdapter implements Closeable {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> final static String ZOOKEEPER_SERVER = &quot;127.0.0.1:2181&quot;;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> final static String ELECTION_PATH = &quot;/dice-elect&quot;;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Dice() throws InterruptedException {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> curator = CuratorFrameworkFactory.newClient(ZOOKEEPER_SERVER,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 2000, 10000, new ExponentialBackoffRetry(1000, 3));</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> curator.start();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> curator.blockUntilConnected();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> leaderSelector = new LeaderSelector(curator, ELECTION_PATH, this);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> leaderSelector.autoRequeue();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> leaderSelector.start();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>In the constructor for Dice, we need to create the curator client. We specify four things when creating the client, the location of the zookeeper service, the session timeout, the connect timeout and the retry policy.</p><p>The session timeout is a zookeeper concept. If the zookeeper server doesn&#x27;t hear anything from the client for this amount of time, any leases which the client holds will be timed out. This is important in leader election. For leader election, the curator client will take a lease on ELECTION_PATH. The first instance to take the lease will become leader and the rest will become followers. However, their claim on the lease will remain in the cue. If the first instance then goes away, due to a crash etc., its session will timeout. Once the session times out, the lease will be released and the next instance in the queue will become the leader. The call to autoRequeue() will make the client queue itself again if it loses the lease for some other reason, such as if it was still alive, but it a garbage collection cycle caused it to lose its session, and thereby its lease. I&#x27;ve set the lease to be quite low so that when we test out leader election, transitions will be quite quick. The optimum length for session timeout depends very much on the use case. The other parameters are the connection timeout, i.e. the amount of time it will spend trying to connect to a zookeeper server before giving up, and the retry policy. The retry policy specifies how the client should respond to transient errors, such as connection loss. Operations that fail with transient errors can be retried, and this argument specifies how often the retries should occur.</p><p>Finally, you&#x27;ll have noticed that Dice now extends LeaderSelectorListenerAdapter and implements Closeable. Closeable is there to close the resource we have initialized in the constructor, the curator client and the leaderSelector. LeaderSelectorListenerAdapter is a callback that the leaderSelector uses to notify the instance that it is now the leader. It is passed as the third argument to the LeaderSelector constructor.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> @Override</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void takeLeadership(CuratorFramework client)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> throws Exception {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> synchronized (this) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> leader = true;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> try {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> while (true) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> this.wait();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> } catch (InterruptedException ie) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Thread.currentThread().interrupt();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> leader = false;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>takeLeadership() is the callback called by LeaderSelector when the instance is leader. It should only return when the instance wants to give up leadership. In our case, we never do so we wait on the current object until we&#x27;re interrupted. To signal to the rest of the program that we are leader we set a volatile boolean called leader to true. This is unset after we are interrupted.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> void playDice() throws InterruptedException {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> while (true) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> while (leader) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Thread.sleep(1000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> System.out.println(&quot;Value = &quot; + (r.nextInt(6) + 1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> + &quot;, isLeader = &quot; + leader);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Finally, we modify the <code>playDice</code> function to only generate random numbers when it is the leader.</p><p>Run two instances of the program in two different terminals. You&#x27;ll see that one becomes leader and prints numbers and the other just sits there.</p><p>Now stop the leader using Control-Z. This will pause the process, but it won&#x27;t kill it. You will be dropped back to the shell in that terminal. After a couple of seconds, the session timeout, you will see that the other instance has become the leader. Zookeeper will guarantee that only one instance is selected as leader at any time.</p><p>Now go back to the shell that the original leader was on and wake up the process using fg. You&#x27;ll see something like the following:</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain">, isLeader </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain">, isLeader </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">^Z</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">+ Stopped mvn exec:java -Dexec.mainClass</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">org.apache.bookkeeper.Dice</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ </span><span class="token function" style="color:#d73a49">fg</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">mvn exec:java -Dexec.mainClass</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">org.apache.bookkeeper.Dice</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain">, isLeader </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Value </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain">, isLeader </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-api">New API<a href="#new-api" class="hash-link" aria-label="Direct link to New API" title="Direct link to New API"></a></h2><p>Since 4.6 BookKeeper provides a new client API which leverages Java8 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html" target="_blank" rel="noopener noreferrer">CompletableFuture</a> facility.
<a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteHandle" target="_blank" rel="noopener noreferrer">WriteHandle</a>, <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteAdvHandle" target="_blank" rel="noopener noreferrer">WriteAdvHandle</a>, <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ReadHandle" target="_blank" rel="noopener noreferrer">ReadHandle</a> are introduced for replacing the generic <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/LedgerHandle" target="_blank" rel="noopener noreferrer">LedgerHandle</a>.</p><blockquote><p>All the new API now is available in <code>org.apache.bookkeeper.client.api</code>. You should only use interfaces defined in this package.</p></blockquote><p><em>Beware</em> that this API in 4.6 is still experimental API and can be subject to changes in next minor releases.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-a-new-client">Create a new client<a href="#create-a-new-client" class="hash-link" aria-label="Direct link to Create a new client" title="Direct link to Create a new client"></a></h3><p>In order to create a new <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/BookKeeper" target="_blank" rel="noopener noreferrer"><code>BookKeeper</code></a> client object, you need to construct a <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/conf/ClientConfiguration" target="_blank" rel="noopener noreferrer"><code>ClientConfiguration</code></a> object and set a <a href="#connection-string">connection string</a> first, and then use <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/BookKeeperBuilder" target="_blank" rel="noopener noreferrer"><code>BookKeeperBuilder</code></a> to build the client.</p><p>Here is an example building the bookkeeper client.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">// construct a client configuration instance</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ClientConfiguration conf = new ClientConfiguration();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">conf.setZkServers(zkConnectionString);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">conf.setZkLedgersRootPath(&quot;/path/to/ledgers/root&quot;);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// build the bookkeeper client</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = BookKeeper.newBuilder(conf)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .statsLogger(...)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .build();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-ledgers">Create ledgers<a href="#create-ledgers" class="hash-link" aria-label="Direct link to Create ledgers" title="Direct link to Create ledgers"></a></h3><p>the easiest way to create a ledger using the java client is via the <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/createbuilder" target="_blank" rel="noopener noreferrer"><code>createbuilder</code></a>. you must specify at least
a <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/digesttype" target="_blank" rel="noopener noreferrer"><code>digesttype</code></a> and a password.</p><p>here&#x27;s an example:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">byte[] password = &quot;some-password&quot;.getBytes();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WriteHandle wh = bk.newCreateLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withDigestType(DigestType.CRC32)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withPassword(password)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withEnsembleSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withWriteQuorumSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withAckQuorumSize(2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute() // execute the creation op</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get(); // wait for the execution to complete</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>A <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteHandle" target="_blank" rel="noopener noreferrer"><code>WriteHandle</code></a> is returned for applications to write and read entries to and from the ledger.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="write-flags">Write flags<a href="#write-flags" class="hash-link" aria-label="Direct link to Write flags" title="Direct link to Write flags"></a></h3><p>You can specify behaviour of the writer by setting <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteFlag" target="_blank" rel="noopener noreferrer"><code>WriteFlags</code></a> at ledger creation type.
These flags are applied only during write operations and are not recorded on metadata.</p><p>Available write flags:</p><table><thead><tr><th align="left">Flag</th><th align="left">Explanation</th><th align="left">Notes</th></tr></thead><tbody><tr><td align="left">DEFERRED_SYNC</td><td align="left">Writes are acknowledged early, without waiting for guarantees of durability</td><td align="left">Data will be only written to the OS page cache, without forcing an fsync.</td></tr></tbody></table><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">byte[] password = &quot;some-password&quot;.getBytes();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WriteHandle wh = bk.newCreateLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withDigestType(DigestType.CRC32)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withPassword(password)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withEnsembleSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withWriteQuorumSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withAckQuorumSize(2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withWriteFlags(DEFERRED_SYNC)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute() // execute the creation op</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get(); // wait for the execution to complete</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="append-entries-to-ledgers">Append entries to ledgers<a href="#append-entries-to-ledgers" class="hash-link" aria-label="Direct link to Append entries to ledgers" title="Direct link to Append entries to ledgers"></a></h3><p>The <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteHandle" target="_blank" rel="noopener noreferrer"><code>WriteHandle</code></a> can be used for applications to append entries to the ledgers.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">WriteHandle wh = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CompletableFuture&lt;Long&gt; addFuture = wh.append(&quot;Some entry data&quot;.getBytes());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 1: you can wait for add to complete synchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">try {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> long entryId = FutureUtils.result(addFuture.get());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">} catch (BKException bke) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // error handling</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 2: you can process the result and exception asynchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">addFuture</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .thenApply(entryId -&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the result</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .exceptionally(cause -&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // handle the exception</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 3: bookkeeper provides a twitter-future-like event listener for processing result and exception asynchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">addFuture.whenComplete(new FutureEventListener() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> @Override</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void onSuccess(long entryId) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the result</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> @Override</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void onFailure(Throwable cause) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // handle the exception</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>The append method supports three representations of a bytes array: the native java <code>byte[]</code>, java nio <code>ByteBuffer</code> and netty <code>ByteBuf</code>.
It is recommended to use <code>ByteBuf</code> as it is more gc friendly.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="open-ledgers">Open ledgers<a href="#open-ledgers" class="hash-link" aria-label="Direct link to Open ledgers" title="Direct link to Open ledgers"></a></h3><p>You can open ledgers to read entries. Opening ledgers is done by <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/openBuilder" target="_blank" rel="noopener noreferrer"><code>openBuilder</code></a>. You must specify the ledgerId and the password
in order to open the ledgers.</p><p>here&#x27;s an example:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">byte[] password = &quot;some-password&quot;.getBytes();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ReadHandle rh = bk.newOpenLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withLedgerId(ledgerId)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withPassword(password)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute() // execute the open op</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get(); // wait for the execution to complete</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>A <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ReadHandle" target="_blank" rel="noopener noreferrer"><code>ReadHandle</code></a> is returned for applications to read entries to and from the ledger.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="recovery-vs-norecovery">Recovery vs NoRecovery<a href="#recovery-vs-norecovery" class="hash-link" aria-label="Direct link to Recovery vs NoRecovery" title="Direct link to Recovery vs NoRecovery"></a></h4><p>By default, the <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/openBuilder" target="_blank" rel="noopener noreferrer"><code>openBuilder</code></a> opens the ledger in a <code>NoRecovery</code> mode. You can open the ledger in <code>Recovery</code> mode by specifying
<code>withRecovery(true)</code> in the open builder.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">byte[] password = &quot;some-password&quot;.getBytes();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ReadHandle rh = bk.newOpenLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withLedgerId(ledgerId)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withPassword(password)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withRecovery(true)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>What is the difference between &quot;Recovery&quot; and &quot;NoRecovery&quot;?</strong></p><p>If you are opening a ledger in &quot;Recovery&quot; mode, it will basically fence and seal the ledger -- no more entries are allowed
to be appended to it. The writer which is currently appending entries to the ledger will fail with <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/BKException.Code#LedgerFencedException" target="_blank" rel="noopener noreferrer"><code>LedgerFencedException</code></a>.</p><p>In constrat, opening a ledger in &quot;NoRecovery&quot; mode, it will not fence and seal the ledger. &quot;NoRecovery&quot; mode is usually used by applications to tailing-read from a ledger.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="read-entries-from-ledgers">Read entries from ledgers<a href="#read-entries-from-ledgers" class="hash-link" aria-label="Direct link to Read entries from ledgers" title="Direct link to Read entries from ledgers"></a></h3><p>The <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ReadHandle" target="_blank" rel="noopener noreferrer"><code>ReadHandle</code></a> returned from the open builder can be used for applications to read entries from the ledgers.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ReadHandle rh = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long startEntryId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long endEntryId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">CompletableFuture&lt;LedgerEntries&gt; readFuture = rh.read(startEntryId, endEntryId);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 1: you can wait for read to complete synchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">try {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> LedgerEntries entries = FutureUtils.result(readFuture.get());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">} catch (BKException bke) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // error handling</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 2: you can process the result and exception asynchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readFuture</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .thenApply(entries -&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the result</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .exceptionally(cause -&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // handle the exception</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> })</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// option 3: bookkeeper provides a twitter-future-like event listener for processing result and exception asynchronously</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">readFuture.whenComplete(new FutureEventListener&lt;&gt;() {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> @Override</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void onSuccess(LedgerEntries entries) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the result</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> @Override</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> public void onFailure(Throwable cause) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // handle the exception</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">});</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Once you are done with processing the <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/LedgerEntries" target="_blank" rel="noopener noreferrer"><code>LedgerEntries</code></a>, you can call <code>#close()</code> on the <code>LedgerEntries</code> instance to
release the buffers held by it.</p><p>Applications are allowed to read any entries between <code>0</code> and <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ReadHandle.html#getLastAddConfirmed" target="_blank" rel="noopener noreferrer"><code>LastAddConfirmed</code></a>. If the applications
attempts to read entries beyond <code>LastAddConfirmed</code>, they will receive <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/BKException.Code#IncorrectParameterException" target="_blank" rel="noopener noreferrer"><code>IncorrectParameterException</code></a>.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="read-unconfirmed-entries-from-ledgers">Read unconfirmed entries from ledgers<a href="#read-unconfirmed-entries-from-ledgers" class="hash-link" aria-label="Direct link to Read unconfirmed entries from ledgers" title="Direct link to Read unconfirmed entries from ledgers"></a></h3><p><code>readUnconfirmed</code> is provided the mechanism for applications to read entries beyond <code>LastAddConfirmed</code>. Applications should be aware of <code>readUnconfirmed</code> doesn&#x27;t provide any
repeatable read consistency.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">CompletableFuture&lt;LedgerEntries&gt; readFuture = rh.readUnconfirmed(startEntryId, endEntryId);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="tailing-reads">Tailing Reads<a href="#tailing-reads" class="hash-link" aria-label="Direct link to Tailing Reads" title="Direct link to Tailing Reads"></a></h3><p>There are two methods for applications to achieve tailing reads: <code>Polling</code> and <code>Long-Polling</code>.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="polling">Polling<a href="#polling" class="hash-link" aria-label="Direct link to Polling" title="Direct link to Polling"></a></h4><p>You can do this in synchronous way:</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ReadHandle rh = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long startEntryId = 0L;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long nextEntryId = startEntryId;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">int numEntriesPerBatch = 4;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">while (!rh.isClosed() || nextEntryId &lt;= rh.getLastAddConfirmed()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> long lac = rh.getLastAddConfirmed();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> if (nextEntryId &gt; lac) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // no more entries are added</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> Thread.sleep(1000);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> lac = rh.readLastAddConfirmed().get();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> continue;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> long endEntryId = Math.min(lac, nextEntryId + numEntriesPerBatch - 1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> LedgerEntries entries = rh.read(nextEntryId, endEntryId).get();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the entries</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> nextEntryId = endEntryId + 1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithStickyNavbar_LWe7" id="long-polling">Long Polling<a href="#long-polling" class="hash-link" aria-label="Direct link to Long Polling" title="Direct link to Long Polling"></a></h4><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">ReadHandle rh = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long startEntryId = 0L;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long nextEntryId = startEntryId;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">int numEntriesPerBatch = 4;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">while (!rh.isClosed() || nextEntryId &lt;= rh.getLastAddConfirmed()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> long lac = rh.getLastAddConfirmed();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> if (nextEntryId &gt; lac) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // no more entries are added</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> try (LastConfirmedAndEntry lacAndEntry = rh.readLastAddConfirmedAndEntry(nextEntryId, 1000, false).get()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> if (lacAndEntry.hasEntry()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the entry</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ++nextEntryId;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> } else {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> long endEntryId = Math.min(lac, nextEntryId + numEntriesPerBatch - 1);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> LedgerEntries entries = rh.read(nextEntryId, endEntryId).get();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> // process the entries</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> nextEntryId = endEntryId + 1;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="delete-ledgers">Delete ledgers<a href="#delete-ledgers" class="hash-link" aria-label="Direct link to Delete ledgers" title="Direct link to Delete ledgers"></a></h3><p>Ledgers can be deleted by using <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/DeleteBuilder" target="_blank" rel="noopener noreferrer"><code>DeleteBuilder</code></a>.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bk.newDeleteLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withLedgerId(ledgerId)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get();</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithStickyNavbar_LWe7" id="relaxing-durability">Relaxing Durability<a href="#relaxing-durability" class="hash-link" aria-label="Direct link to Relaxing Durability" title="Direct link to Relaxing Durability"></a></h3><p>In BookKeeper by default each write will be acklowledged to the client if and only if it has been persisted durably (fsync called on the file system) by a quorum of bookies.
In this case the LastAddConfirmed pointer is updated on the writer side, this is the guarantee for the writer that data will not be lost and it will
be always readable by other clients.</p><p>On the client side you can temporary relax this constraint by using the <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/WriteFlag" target="_blank" rel="noopener noreferrer"><code>DEFERRED_SYNC</code></a> Write flag. Using this flag bookies will acknowledge each entry after
writing the entry to SO buffers without waiting for an fsync.
In this case the LastAddConfirmed pointer is not advanced to the writer side neither is updated on the reader&#x27;s side, this is because <strong>there is some chance to lose the entry</strong>.
Such entries will be still readable using readUnconfirmed() API, but they won&#x27;t be readable using Long Poll reads or regular read() API.</p><p>In order to get guarantees of durability the writer must use explicitly the <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ForceableHandle" target="_blank" rel="noopener noreferrer">force()</a> API which will return only after all the bookies in the ensemble acknowledge the call after
performing an fsync to the disk which is storing the journal.
This way the LastAddConfirmed pointer is advanced on the writer side and it will be eventually available to the readers.</p><p>The <em>close()</em> operation on the writer writes on ledger&#x27;s metadata the current LastAddConfirmed pointer, <strong>it is up to the application to call force() before issuing the close command</strong>.
In case that you never call explicitly <a href="https://bookkeeper.apache.org//docs/latest/api/javadoc/org/apache/bookkeeper/client/api/ForceableHandle" target="_blank" rel="noopener noreferrer">force()</a> the LastAddConfirmed will remain unset (-1) on ledger metadata and regular readers won&#x27;t be able to access data.</p><div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">BookKeeper bk = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">long ledgerId = ...;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WriteHandle wh = bk.newCreateLedgerOp()</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withDigestType(DigestType.CRC32)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withPassword(password)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withEnsembleSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withWriteQuorumSize(3)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withAckQuorumSize(2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .withWriteFlags(DEFERRED_SYNC)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .execute() // execute the creation op</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> .get(); // wait for the execution to complete</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">wh.force().get(); // wait for fsync, make data available to readers and to the replicator</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">wh.close(); // seal the ledger</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><a class="pagination-nav__link pagination-nav__link--prev" href="/docs/4.9.2/api/overview"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">BookKeeper API</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/docs/4.9.2/api/ledger-adv-api"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">The Advanced Ledger API</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#the-java-ledger-api-client" class="table-of-contents__link toc-highlight">The Java ledger API client</a></li><li><a href="#installation" class="table-of-contents__link toc-highlight">Installation</a><ul><li><a href="#maven" class="table-of-contents__link toc-highlight">Maven</a></li><li><a href="#gradle" class="table-of-contents__link toc-highlight">Gradle</a></li></ul></li><li><a href="#connection-string" class="table-of-contents__link toc-highlight">Connection string</a></li><li><a href="#creating-a-new-client" class="table-of-contents__link toc-highlight">Creating a new client</a></li><li><a href="#creating-ledgers" class="table-of-contents__link toc-highlight">Creating ledgers</a><ul><li><a href="#create-ledgers-asynchronously" class="table-of-contents__link toc-highlight">Create ledgers asynchronously</a></li></ul></li><li><a href="#adding-entries-to-ledgers" class="table-of-contents__link toc-highlight">Adding entries to ledgers</a><ul><li><a href="#add-entries-asynchronously" class="table-of-contents__link toc-highlight">Add entries asynchronously</a></li></ul></li><li><a href="#reading-entries-from-ledgers" class="table-of-contents__link toc-highlight">Reading entries from ledgers</a><ul><li><a href="#reading-entries-after-the-lastaddconfirmed-range" class="table-of-contents__link toc-highlight">Reading entries after the LastAddConfirmed range</a></li></ul></li><li><a href="#deleting-ledgers" class="table-of-contents__link toc-highlight">Deleting ledgers</a><ul><li><a href="#delete-entries-asynchronously" class="table-of-contents__link toc-highlight">Delete entries asynchronously</a></li></ul></li><li><a href="#simple-example" class="table-of-contents__link toc-highlight">Simple example</a></li><li><a href="#example-application" class="table-of-contents__link toc-highlight">Example application</a><ul><li><a href="#setup" class="table-of-contents__link toc-highlight">Setup</a></li><li><a href="#goal" class="table-of-contents__link toc-highlight">Goal</a></li><li><a href="#the-base-application" class="table-of-contents__link toc-highlight">The base application</a></li><li><a href="#leaders-and-followers-and-a-bit-of-background" class="table-of-contents__link toc-highlight">Leaders and followers (and a bit of background)</a></li><li><a href="#why-not-just-use-zookeeper" class="table-of-contents__link toc-highlight">Why not just use ZooKeeper?</a></li><li><a href="#electing-a-leader" class="table-of-contents__link toc-highlight">Electing a leader</a></li></ul></li><li><a href="#new-api" class="table-of-contents__link toc-highlight">New API</a><ul><li><a href="#create-a-new-client" class="table-of-contents__link toc-highlight">Create a new client</a></li><li><a href="#create-ledgers" class="table-of-contents__link toc-highlight">Create ledgers</a></li><li><a href="#write-flags" class="table-of-contents__link toc-highlight">Write flags</a></li><li><a href="#append-entries-to-ledgers" class="table-of-contents__link toc-highlight">Append entries to ledgers</a></li><li><a href="#open-ledgers" class="table-of-contents__link toc-highlight">Open ledgers</a></li><li><a href="#read-entries-from-ledgers" class="table-of-contents__link toc-highlight">Read entries from ledgers</a></li><li><a href="#read-unconfirmed-entries-from-ledgers" class="table-of-contents__link toc-highlight">Read unconfirmed entries from ledgers</a></li><li><a href="#tailing-reads" class="table-of-contents__link toc-highlight">Tailing Reads</a></li><li><a href="#delete-ledgers" class="table-of-contents__link toc-highlight">Delete ledgers</a></li><li><a href="#relaxing-durability" class="table-of-contents__link toc-highlight">Relaxing Durability</a></li></ul></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Documentation</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/overview">Overview</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/getting-started/installation">Getting started</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/deployment/manual">Deployment</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/admin/bookies">Administration</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/api/overview">API</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/security/overview">Security</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/development/protocol">Development</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/reference/config">Reference</a></li></ul></div><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/community/mailing-lists">Mailing lists</a></li><li class="footer__item"><a class="footer__link-item" href="/community/slack">Slack</a></li><li class="footer__item"><a href="https://github.com/apache/bookkeeper" target="_blank" rel="noopener noreferrer" class="footer__link-item">Github<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://twitter.com/asfbookkeeper" target="_blank" rel="noopener noreferrer" class="footer__link-item">Twitter<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Project</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/project/who">Who are we?</a></li><li class="footer__item"><a class="footer__link-item" href="/project/bylaws">Bylaws</a></li><li class="footer__item"><a href="https://apache.org/licenses" target="_blank" rel="noopener noreferrer" class="footer__link-item">License<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/project/privacy">Privacy policy</a></li><li class="footer__item"><a href="https://www.apache.org/foundation/sponsorship.html" target="_blank" rel="noopener noreferrer" class="footer__link-item">Sponsorship<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.apache.org/foundation/thanks.html" target="_blank" rel="noopener noreferrer" class="footer__link-item">Thanks<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright"><footer class="footer">
<div class="container">
<div class="content has-text-centered">
<p>
Copyright &copy; 2016 - 2024 <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>
</div></div></div></footer></div>
<script src="/assets/js/runtime~main.435d5f64.js"></script>
<script src="/assets/js/main.0f234beb.js"></script>
</body>
</html>