<!-- CANARY: REQ=REQ-DOCS-001; FEATURE="Docs"; ASPECT=Documentation; STATUS=TESTED; OWNER=docs; UPDATED=2026-01-28 -->
<h2 id="backup-and-restore-guide" class="position-relative d-flex align-items-center group">
<span>Backup and Restore Guide</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="backup-and-restore-guide"
aria-haspopup="dialog"
aria-label="Share link: Backup and Restore Guide">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h2><div id="headingShareModal" class="heading-share-modal" role="dialog" aria-modal="true" aria-labelledby="headingShareTitle" hidden>
<div class="hsm-dialog" role="document">
<div class="hsm-header">
<h2 id="headingShareTitle" class="h6 mb-0 fw-bold">Share this section</h2>
<button type="button" class="hsm-close" aria-label="Close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="hsm-body">
<label for="headingShareInput" class="form-label small text-muted mb-1 text-uppercase fw-bold" style="font-size: 0.7rem; letter-spacing: 0.5px;">Permalink</label>
<div class="input-group mb-4 hsm-url-group">
<input id="headingShareInput" type="text" class="form-control font-monospace" readonly aria-readonly="true" style="font-size: 0.85rem;" />
<button class="btn btn-primary hsm-copy" type="button" aria-label="Copy" title="Copy">
<i class="fa-duotone fa-clipboard" aria-hidden="true"></i>
</button>
</div>
<div class="small fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem; letter-spacing: 0.5px;">Share via</div>
<div class="hsm-share-grid">
<a id="share-twitter" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-twitter me-2"></i>Twitter
</a>
<a id="share-linkedin" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-linkedin me-2"></i>LinkedIn
</a>
<a id="share-facebook" class="btn btn-outline-secondary w-100" target="_blank" rel="noopener noreferrer">
<i class="fa-brands fa-facebook me-2"></i>Facebook
</a>
</div>
</div>
</div>
</div>
<style>
.heading-share-modal {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.6);
z-index: 1050;
padding: 1rem;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.heading-share-modal[hidden] { display: none !important; }
.hsm-dialog {
max-width: 420px;
width: 100%;
background: var(--bs-body-bg, #fff);
color: var(--bs-body-color, #212529);
border: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
border-radius: 1rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
animation: hsm-fade-in 0.2s ease-out;
}
@keyframes hsm-fade-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
[data-bs-theme="dark"] .hsm-dialog {
background: #1e293b;
border-color: rgba(255,255,255,0.1);
color: #f8f9fa;
}
.hsm-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid var(--bs-border-color, rgba(0,0,0,0.1));
background: rgba(0,0,0,0.02);
}
[data-bs-theme="dark"] .hsm-header {
background: rgba(255,255,255,0.02);
border-color: rgba(255,255,255,0.1);
}
.hsm-close {
background: transparent;
border: none;
color: inherit;
opacity: 0.5;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 1.2rem;
line-height: 1;
transition: opacity 0.2s;
}
.hsm-close:hover {
opacity: 1;
}
.hsm-body {
padding: 1.5rem;
}
.hsm-url-group {
display: flex !important;
align-items: stretch;
}
.hsm-url-group .form-control {
flex: 1;
min-width: 0;
margin: 0;
background: var(--bs-secondary-bg, #f8f9fa);
border-color: var(--bs-border-color, #dee2e6);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
height: 42px;
}
.hsm-url-group .btn {
flex: 0 0 auto;
margin: 0;
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
height: 42px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1.25rem;
z-index: 2;
}
[data-bs-theme="dark"] .hsm-url-group .form-control {
background: #0f172a;
border-color: #334155;
color: #e2e8f0;
}
.hsm-share-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.hsm-share-grid .btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.9rem;
padding: 0.6rem;
border-color: var(--bs-border-color);
width: 100%;
}
[data-bs-theme="dark"] .hsm-share-grid .btn {
color: #e2e8f0;
border-color: #475569;
}
[data-bs-theme="dark"] .hsm-share-grid .btn:hover {
background: #334155;
border-color: #cbd5e1;
}
</style>
<script>
(function(){
const modal = document.getElementById('headingShareModal');
if(!modal) return;
const input = modal.querySelector('#headingShareInput');
const copyBtn = modal.querySelector('.hsm-copy');
const twitter = modal.querySelector('#share-twitter');
const linkedin = modal.querySelector('#share-linkedin');
const facebook = modal.querySelector('#share-facebook');
const closeBtn = modal.querySelector('.hsm-close');
let lastFocus=null;
let trapBound=false;
function buildUrl(id){ return window.location.origin + window.location.pathname + '#' + id; }
function isOpen(){ return !modal.hasAttribute('hidden'); }
function hydrate(id){
const url=buildUrl(id);
input.value=url;
const enc=encodeURIComponent(url);
const text=encodeURIComponent(document.title);
if(twitter) twitter.href=`https://twitter.com/intent/tweet?url=${enc}&text=${text}`;
if(linkedin) linkedin.href=`https://www.linkedin.com/sharing/share-offsite/?url=${enc}`;
if(facebook) facebook.href=`https://www.facebook.com/sharer/sharer.php?u=${enc}`;
}
function openModal(id){
lastFocus=document.activeElement;
hydrate(id);
if(!isOpen()){
modal.removeAttribute('hidden');
}
requestAnimationFrame(()=>{ input.focus(); });
trapFocus();
}
function closeModal(){
if(!isOpen()) return;
modal.setAttribute('hidden','');
if(lastFocus && typeof lastFocus.focus==='function') lastFocus.focus();
}
function copyCurrent(){
try{ navigator.clipboard.writeText(input.value).then(()=>feedback(true),()=>fallback()); }
catch(e){ fallback(); }
}
function fallback(){ input.select(); try{ document.execCommand('copy'); feedback(true);}catch(e){ feedback(false);} }
function feedback(ok){ if(!copyBtn) return; const icon=copyBtn.querySelector('i'); if(!icon) return; const prev=copyBtn.getAttribute('data-prev')||icon.className; if(!copyBtn.getAttribute('data-prev')) copyBtn.setAttribute('data-prev',prev); icon.className= ok ? 'fa-duotone fa-clipboard-check':'fa-duotone fa-circle-exclamation'; setTimeout(()=>{ icon.className=prev; },1800); }
function handleShareClick(e){ e.preventDefault(); const btn=e.currentTarget; const id=btn.getAttribute('data-share-target'); if(id) openModal(id); }
function bindShareButtons(){
document.querySelectorAll('.h-share').forEach(btn=>{
if(!btn.dataset.hShareBound){ btn.addEventListener('click', handleShareClick); btn.dataset.hShareBound='1'; }
});
}
bindShareButtons();
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', bindShareButtons);
} else {
requestAnimationFrame(bindShareButtons);
}
document.addEventListener('click', function(e){
const shareBtn=e.target.closest && e.target.closest('.h-share');
if(shareBtn && !shareBtn.dataset.hShareBound){ handleShareClick.call(shareBtn, e); }
}, true);
document.addEventListener('click', e=>{
if(e.target===modal) closeModal();
if(e.target.closest && e.target.closest('.hsm-close')){ e.preventDefault(); closeModal(); }
if(copyBtn && (e.target===copyBtn || (e.target.closest && e.target.closest('.hsm-copy')))) { e.preventDefault(); copyCurrent(); }
});
document.addEventListener('keydown', e=>{ if(e.key==='Escape' && isOpen()) closeModal(); });
function trapFocus(){
if(trapBound) return;
trapBound=true;
modal.addEventListener('keydown', f=>{ if(f.key==='Tab' && isOpen()){ const focusable=[...modal.querySelectorAll('a[href],button,input,textarea,select,[tabindex]:not([tabindex="-1"])')].filter(el=>!el.hasAttribute('disabled')); if(!focusable.length) return; const first=focusable[0]; const last=focusable[focusable.length-1]; if(f.shiftKey && document.activeElement===first){ f.preventDefault(); last.focus(); } else if(!f.shiftKey && document.activeElement===last){ f.preventDefault(); first.focus(); } } });
}
if(closeBtn) closeBtn.addEventListener('click', e=>{ e.preventDefault(); closeModal(); });
})();
</script><p>This guide covers comprehensive backup and restore strategies for Geode databases. Learn how to implement online and offline backups, full and incremental backups, point-in-time recovery, and disaster recovery planning.</p>
<h3 id="overview" class="position-relative d-flex align-items-center group">
<span>Overview</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="overview"
aria-haspopup="dialog"
aria-label="Share link: Overview">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><p>Geode provides multiple backup strategies to protect your data:</p>
<table>
<thead>
<tr>
<th>Backup Type</th>
<th>Description</th>
<th>Use Case</th>
</tr>
</thead>
<tbody>
<tr>
<td>Online Backup</td>
<td>No downtime required</td>
<td>Production systems</td>
</tr>
<tr>
<td>Offline Backup</td>
<td>Database stopped</td>
<td>Maintenance windows</td>
</tr>
<tr>
<td>Full Backup</td>
<td>Complete database copy</td>
<td>Weekly/monthly backups</td>
</tr>
<tr>
<td>Incremental Backup</td>
<td>Changes since last backup</td>
<td>Daily backups</td>
</tr>
<tr>
<td>Point-in-Time</td>
<td>Restore to specific moment</td>
<td>Data recovery</td>
</tr>
<tr>
<td>Snapshot</td>
<td>Instant copy</td>
<td>Testing, development</td>
</tr>
</tbody>
</table>
<h3 id="backup-architecture" class="position-relative d-flex align-items-center group">
<span>Backup Architecture</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="backup-architecture"
aria-haspopup="dialog"
aria-label="Share link: Backup Architecture">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Geode Database
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> +-- Data Files (*.gdb)
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> +-- Transaction Logs (*.wal)
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> +-- Configuration (geode.conf)
</span></span><span class="line"><span class="cl"> |
</span></span><span class="line"><span class="cl"> +-- Metadata (schemas, indexes)
</span></span></code></pre></div>
<h3 id="online-vs-offline-backups" class="position-relative d-flex align-items-center group">
<span>Online vs Offline Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="online-vs-offline-backups"
aria-haspopup="dialog"
aria-label="Share link: Online vs Offline Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="online-backups-hot-backup" class="position-relative d-flex align-items-center group">
<span>Online Backups (Hot Backup)</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="online-backups-hot-backup"
aria-haspopup="dialog"
aria-label="Share link: Online Backups (Hot Backup)">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Online backups allow you to back up the database while it’s running and serving traffic.</p>
<p><strong>Advantages</strong>:</p>
<ul>
<li>No downtime</li>
<li>Consistent snapshot</li>
<li>Suitable for 24/7 operations</li>
</ul>
<p><strong>CLI Command</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Create online backup</span>
</span></span><span class="line"><span class="cl">geode backup create <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /backups/geode-<span class="k">$(</span>date +%Y%m%d-%H%M%S<span class="k">)</span>.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compress <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --verify
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># With specific connection</span>
</span></span><span class="line"><span class="cl">geode backup create <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --host localhost:3141 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /backups/full-backup.backup
</span></span></code></pre></div><p><strong>Multi-Language Online Backup Examples</strong>:</p>
<div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883800779365" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883800779365-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883800779365-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883800779365-tab-0"
aria-selected="true"
>
Go
</button>
</li><li class="nav-item" role="presentation">
<button
class="nav-link"
id="tabs-1774880883800779365-tab-1-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883800779365-tab-1"
type="button"
role="tab"
aria-controls="tabs-1774880883800779365-tab-1"
aria-selected="false"
>
Python
</button>
</li><li class="nav-item" role="presentation">
<button
class="nav-link"
id="tabs-1774880883800779365-tab-2-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883800779365-tab-2"
type="button"
role="tab"
aria-controls="tabs-1774880883800779365-tab-2"
aria-selected="false"
>
Rust
</button>
</li><li class="nav-item" role="presentation">
<button
class="nav-link"
id="tabs-1774880883800779365-tab-3-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883800779365-tab-3"
type="button"
role="tab"
aria-controls="tabs-1774880883800779365-tab-3"
aria-selected="false"
>
Bash
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883800779365-content"><div
class="tab-pane fade show active"
id="tabs-1774880883800779365-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883800779365-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"context"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"database/sql"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"log"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">_</span> <span class="s">"geodedb.com/geode"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">createOnlineBackup</span><span class="p">(</span><span class="nx">db</span> <span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span><span class="p">,</span> <span class="nx">backupPath</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ctx</span> <span class="o">:=</span> <span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Start backup
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">db</span><span class="p">.</span><span class="nf">ExecContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"CALL geode.backup.create($path, $compress)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">backupPath</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"backup failed: %w"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Verify backup
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">rows</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">db</span><span class="p">.</span><span class="nf">QueryContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s">"CALL geode.backup.verify($path)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">backupPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"verification failed: %w"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">valid</span> <span class="kt">bool</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">checksum</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Next</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rows</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="o">&</span><span class="nx">valid</span><span class="p">,</span> <span class="o">&</span><span class="nx">checksum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">valid</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"backup verification failed"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Backup verified: checksum=%s"</span><span class="p">,</span> <span class="nx">checksum</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">db</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">sql</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">"geode"</span><span class="p">,</span> <span class="s">"localhost:3141"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">db</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">backupPath</span> <span class="o">:=</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"/backups/geode-%s.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Format</span><span class="p">(</span><span class="s">"20060102-150405"</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">createOnlineBackup</span><span class="p">(</span><span class="nx">db</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatalf</span><span class="p">(</span><span class="s">"Backup failed: %v"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Backup created successfully: %s"</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
</div><div
class="tab-pane fade"
id="tabs-1774880883800779365-tab-1"
role="tabpanel"
aria-labelledby="tabs-1774880883800779365-tab-1-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">create_online_backup</span><span class="p">(</span><span class="n">backup_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create an online backup without stopping the database."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Start backup</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Starting online backup to </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CALL geode.backup.create($path, $compress)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">,</span> <span class="s2">"compress"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Verify backup integrity</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CALL geode.backup.verify($path)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">row</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">valid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s1">'valid'</span><span class="p">]</span><span class="o">.</span><span class="n">as_bool</span>
</span></span><span class="line"><span class="cl"> <span class="n">checksum</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s1">'checksum'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span>
</span></span><span class="line"><span class="cl"> <span class="n">size_mb</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s1">'size_bytes'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">valid</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Backup verified successfully"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Checksum: </span><span class="si">{</span><span class="n">checksum</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Size: </span><span class="si">{</span><span class="n">size_mb</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> MB"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">"Backup verification failed"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Online backup complete: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"/backups/geode-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">create_online_backup</span><span class="p">(</span><span class="n">backup_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
</div><div
class="tab-pane fade"
id="tabs-1774880883800779365-tab-2"
role="tabpanel"
aria-labelledby="tabs-1774880883800779365-tab-2-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">geode_client</span>::<span class="p">{</span><span class="n">Client</span><span class="p">,</span><span class="w"> </span><span class="n">Value</span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="n">chrono</span>::<span class="n">Local</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="cp">#[tokio::main]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">async</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">std</span>::<span class="n">error</span>::<span class="n">Error</span><span class="o">>></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">client</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Client</span>::<span class="n">new</span><span class="p">(</span><span class="s">"127.0.0.1"</span><span class="p">,</span><span class="w"> </span><span class="mi">3141</span><span class="p">).</span><span class="n">skip_verify</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">conn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">client</span><span class="p">.</span><span class="n">connect</span><span class="p">().</span><span class="k">await</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">timestamp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Local</span>::<span class="n">now</span><span class="p">().</span><span class="n">format</span><span class="p">(</span><span class="s">"%Y%m%d-%H%M%S"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">backup_path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">format!</span><span class="p">(</span><span class="s">"/backups/geode-</span><span class="si">{}</span><span class="s">.backup"</span><span class="p">,</span><span class="w"> </span><span class="n">timestamp</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Starting online backup to </span><span class="si">{}</span><span class="s">..."</span><span class="p">,</span><span class="w"> </span><span class="n">backup_path</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Create backup
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">params</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">"path"</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">Value</span>::<span class="n">string</span><span class="p">(</span><span class="o">&</span><span class="n">backup_path</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">"compress"</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">Value</span>::<span class="kt">bool</span><span class="p">(</span><span class="kc">true</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">conn</span><span class="p">.</span><span class="n">query_with_params</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"CALL geode.backup.create($path, $compress)"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">&</span><span class="n">params</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">).</span><span class="k">await</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Verify backup
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">verify_params</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashMap</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">verify_params</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="s">"path"</span><span class="p">.</span><span class="n">to_string</span><span class="p">(),</span><span class="w"> </span><span class="n">Value</span>::<span class="n">string</span><span class="p">(</span><span class="o">&</span><span class="n">backup_path</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">result</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">conn</span><span class="p">.</span><span class="n">query_with_params</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"CALL geode.backup.verify($path)"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="o">&</span><span class="n">verify_params</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">).</span><span class="k">await</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">row</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="n">rows</span><span class="p">.</span><span class="n">first</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">valid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">row</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"valid"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">as_bool</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">checksum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">row</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"checksum"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">().</span><span class="n">as_string</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">valid</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Backup verified: checksum=</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">checksum</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="s">"Backup verification failed"</span><span class="p">.</span><span class="n">into</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Online backup complete: </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">backup_path</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div>
</div><div
class="tab-pane fade"
id="tabs-1774880883800779365-tab-3"
role="tabpanel"
aria-labelledby="tabs-1774880883800779365-tab-3-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1"># Online backup script</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"/backups"</span>
</span></span><span class="line"><span class="cl"><span class="nv">TIMESTAMP</span><span class="o">=</span><span class="k">$(</span>date +%Y%m%d-%H%M%S<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">BACKUP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">/geode-</span><span class="si">${</span><span class="nv">TIMESTAMP</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"><span class="nv">GEODE_HOST</span><span class="o">=</span><span class="s2">"localhost:3141"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">"Starting online backup..."</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create backup</span>
</span></span><span class="line"><span class="cl">geode backup create <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --host <span class="s2">"</span><span class="si">${</span><span class="nv">GEODE_HOST</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compress <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --verify
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Check result</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl"> <span class="nv">SIZE</span><span class="o">=</span><span class="k">$(</span>du -h <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="p">|</span> cut -f1<span class="k">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"Backup complete: </span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2"> (</span><span class="si">${</span><span class="nv">SIZE</span><span class="si">}</span><span class="s2">)"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Keep only last 7 daily backups</span>
</span></span><span class="line"><span class="cl"> find <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">"</span> -name <span class="s2">"geode-*.backup"</span> -mtime +7 -delete
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"Cleaned up old backups"</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"Backup failed!"</span>
</span></span><span class="line"><span class="cl"> <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div>
</div></div>
</div>
<h4 id="offline-backups-cold-backup" class="position-relative d-flex align-items-center group">
<span>Offline Backups (Cold Backup)</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="offline-backups-cold-backup"
aria-haspopup="dialog"
aria-label="Share link: Offline Backups (Cold Backup)">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Offline backups require stopping the database but guarantee complete consistency.</p>
<p><strong>CLI Commands</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Stop Geode</span>
</span></span><span class="line"><span class="cl">systemctl stop geode
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create backup (filesystem copy)</span>
</span></span><span class="line"><span class="cl">tar -czvf /backups/geode-offline-<span class="k">$(</span>date +%Y%m%d<span class="k">)</span>.tar.gz /var/lib/geode/data
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restart Geode</span>
</span></span><span class="line"><span class="cl">systemctl start geode
</span></span></code></pre></div><p><strong>When to Use Offline Backups</strong>:</p>
<ul>
<li>Major version upgrades</li>
<li>Schema migrations</li>
<li>Hardware maintenance</li>
<li>Compliance requirements</li>
</ul>
<h3 id="full-backups" class="position-relative d-flex align-items-center group">
<span>Full Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="full-backups"
aria-haspopup="dialog"
aria-label="Share link: Full Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="creating-full-backups" class="position-relative d-flex align-items-center group">
<span>Creating Full Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="creating-full-backups"
aria-haspopup="dialog"
aria-label="Share link: Creating Full Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>A full backup contains the complete database state.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Full backup with metadata</span>
</span></span><span class="line"><span class="cl">geode backup full <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /backups/full-<span class="k">$(</span>date +%Y%m%d<span class="k">)</span>.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --include-metadata <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --include-indexes <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compress gzip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compression-level <span class="m">6</span>
</span></span></code></pre></div>
<h4 id="full-backup-schedule" class="position-relative d-flex align-items-center group">
<span>Full Backup Schedule</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="full-backup-schedule"
aria-haspopup="dialog"
aria-label="Share link: Full Backup Schedule">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">create_full_backup</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create a full backup with all data and metadata."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">backup_dir</span> <span class="o">=</span> <span class="s2">"/backups/full"</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">backup_dir</span><span class="si">}</span><span class="s2">/geode-full-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Create full backup with all options</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.backup.full($path, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> include_metadata: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> include_indexes: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> compression: 'gzip',
</span></span></span><span class="line"><span class="cl"><span class="s2"> compression_level: 6
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Get backup info</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CALL geode.backup.info($path)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">info</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Full backup created: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Nodes: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'node_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Relationships: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'relationship_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Size: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'size_bytes'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span><span class="p">)</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> MB"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Duration: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'duration_ms'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">}</span><span class="s2"> ms"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">create_full_backup</span><span class="p">())</span>
</span></span></code></pre></div>
<h3 id="incremental-backups" class="position-relative d-flex align-items-center group">
<span>Incremental Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="incremental-backups"
aria-haspopup="dialog"
aria-label="Share link: Incremental Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="understanding-incremental-backups" class="position-relative d-flex align-items-center group">
<span>Understanding Incremental Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="understanding-incremental-backups"
aria-haspopup="dialog"
aria-label="Share link: Understanding Incremental Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Incremental backups only store changes since the last backup, reducing storage and time.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Day 1: Full Backup (10GB)
</span></span><span class="line"><span class="cl">Day 2: Incremental (+500MB changes)
</span></span><span class="line"><span class="cl">Day 3: Incremental (+300MB changes)
</span></span><span class="line"><span class="cl">Day 4: Incremental (+400MB changes)
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">Day 7: New Full Backup
</span></span></code></pre></div>
<h4 id="creating-incremental-backups" class="position-relative d-flex align-items-center group">
<span>Creating Incremental Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="creating-incremental-backups"
aria-haspopup="dialog"
aria-label="Share link: Creating Incremental Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Create incremental backup based on last full backup</span>
</span></span><span class="line"><span class="cl">geode backup incremental <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --base /backups/full/geode-full-20260125.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /backups/incremental/geode-incr-<span class="k">$(</span>date +%Y%m%d-%H%M%S<span class="k">)</span>.backup
</span></span></code></pre></div><div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883815514356" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883815514356-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883815514356-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883815514356-tab-0"
aria-selected="true"
>
Python
</button>
</li><li class="nav-item" role="presentation">
<button
class="nav-link"
id="tabs-1774880883815514356-tab-1-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883815514356-tab-1"
type="button"
role="tab"
aria-controls="tabs-1774880883815514356-tab-1"
aria-selected="false"
>
Go
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883815514356-content"><div
class="tab-pane fade show active"
id="tabs-1774880883815514356-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883815514356-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">IncrementalBackupManager</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">backup_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">backup_dir</span> <span class="o">=</span> <span class="n">backup_dir</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">full_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"full"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">incr_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"incremental"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">state_file</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"backup_state.json"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">full_dir</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">incr_dir</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">_load_state</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_file</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span><span class="s2">"last_full"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="s2">"last_lsn"</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">_save_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_file</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">create_full_backup</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create a new full backup."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">full_dir</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"full-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Create full backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.backup.full($path, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> include_metadata: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> compression: 'gzip'
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">lsn</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'end_lsn'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Update state</span>
</span></span><span class="line"><span class="cl"> <span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_load_state</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">state</span><span class="p">[</span><span class="s2">"last_full"</span><span class="p">]</span> <span class="o">=</span> <span class="n">backup_path</span>
</span></span><span class="line"><span class="cl"> <span class="n">state</span><span class="p">[</span><span class="s2">"last_lsn"</span><span class="p">]</span> <span class="o">=</span> <span class="n">lsn</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">_save_state</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Full backup created: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" End LSN: </span><span class="si">{</span><span class="n">lsn</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">backup_path</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">create_incremental_backup</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create an incremental backup since last backup."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_load_state</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">state</span><span class="p">[</span><span class="s2">"last_full"</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"No full backup exists. Creating full backup first..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_full_backup</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">incr_dir</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"incr-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Create incremental backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.backup.incremental($path, $from_lsn, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> compression: 'gzip'
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">,</span> <span class="s2">"from_lsn"</span><span class="p">:</span> <span class="n">state</span><span class="p">[</span><span class="s2">"last_lsn"</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">row</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="n">changes</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s1">'change_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl"> <span class="n">end_lsn</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s1">'end_lsn'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">changes</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"No changes since last backup"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">backup_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Update state</span>
</span></span><span class="line"><span class="cl"> <span class="n">state</span><span class="p">[</span><span class="s2">"last_lsn"</span><span class="p">]</span> <span class="o">=</span> <span class="n">end_lsn</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">_save_state</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Incremental backup created: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Changes: </span><span class="si">{</span><span class="n">changes</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" End LSN: </span><span class="si">{</span><span class="n">end_lsn</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">backup_path</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">manager</span> <span class="o">=</span> <span class="n">IncrementalBackupManager</span><span class="p">(</span><span class="s2">"/backups/geode"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Weekly: Create full backup</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># await manager.create_full_backup()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Daily: Create incremental backup</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">manager</span><span class="o">.</span><span class="n">create_incremental_backup</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
</div><div
class="tab-pane fade"
id="tabs-1774880883815514356-tab-1"
role="tabpanel"
aria-labelledby="tabs-1774880883815514356-tab-1-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"context"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"database/sql"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"encoding/json"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"log"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"path/filepath"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"time"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">_</span> <span class="s">"geodedb.com/geode"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">BackupState</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">LastFull</span> <span class="kt">string</span> <span class="s">`json:"last_full"`</span>
</span></span><span class="line"><span class="cl"> <span class="nx">LastLSN</span> <span class="kt">int64</span> <span class="s">`json:"last_lsn"`</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">IncrementalBackupManager</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">backupDir</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl"> <span class="nx">db</span> <span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewIncrementalBackupManager</span><span class="p">(</span><span class="nx">backupDir</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">db</span> <span class="o">*</span><span class="nx">sql</span><span class="p">.</span><span class="nx">DB</span><span class="p">)</span> <span class="o">*</span><span class="nx">IncrementalBackupManager</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">os</span><span class="p">.</span><span class="nf">MkdirAll</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"full"</span><span class="p">),</span> <span class="mo">0755</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">os</span><span class="p">.</span><span class="nf">MkdirAll</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"incremental"</span><span class="p">),</span> <span class="mo">0755</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">&</span><span class="nx">IncrementalBackupManager</span><span class="p">{</span><span class="nx">backupDir</span><span class="p">:</span> <span class="nx">backupDir</span><span class="p">,</span> <span class="nx">db</span><span class="p">:</span> <span class="nx">db</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">m</span> <span class="o">*</span><span class="nx">IncrementalBackupManager</span><span class="p">)</span> <span class="nf">loadState</span><span class="p">()</span> <span class="nx">BackupState</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">stateFile</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"backup_state.json"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">data</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">ReadFile</span><span class="p">(</span><span class="nx">stateFile</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">BackupState</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">state</span> <span class="nx">BackupState</span>
</span></span><span class="line"><span class="cl"> <span class="nx">json</span><span class="p">.</span><span class="nf">Unmarshal</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="o">&</span><span class="nx">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">state</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">m</span> <span class="o">*</span><span class="nx">IncrementalBackupManager</span><span class="p">)</span> <span class="nf">saveState</span><span class="p">(</span><span class="nx">state</span> <span class="nx">BackupState</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">stateFile</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"backup_state.json"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">data</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">json</span><span class="p">.</span><span class="nf">MarshalIndent</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="s">" "</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">os</span><span class="p">.</span><span class="nf">WriteFile</span><span class="p">(</span><span class="nx">stateFile</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="mo">0644</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">m</span> <span class="o">*</span><span class="nx">IncrementalBackupManager</span><span class="p">)</span> <span class="nf">CreateFullBackup</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">timestamp</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Format</span><span class="p">(</span><span class="s">"20060102-150405"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">backupPath</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"full"</span><span class="p">,</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"full-%s.backup"</span><span class="p">,</span> <span class="nx">timestamp</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">rows</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">m</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">QueryContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="s">`
</span></span></span><span class="line"><span class="cl"><span class="s"> CALL geode.backup.full($1, {include_metadata: true, compression: 'gzip'})
</span></span></span><span class="line"><span class="cl"><span class="s"> `</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Next</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">endLSN</span> <span class="kt">int64</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rows</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="o">&</span><span class="nx">endLSN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">state</span> <span class="o">:=</span> <span class="nx">BackupState</span><span class="p">{</span><span class="nx">LastFull</span><span class="p">:</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="nx">LastLSN</span><span class="p">:</span> <span class="nx">endLSN</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">m</span><span class="p">.</span><span class="nf">saveState</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Full backup created: %s (LSN: %d)"</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="nx">endLSN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"backup failed"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">m</span> <span class="o">*</span><span class="nx">IncrementalBackupManager</span><span class="p">)</span> <span class="nf">CreateIncrementalBackup</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">state</span> <span class="o">:=</span> <span class="nx">m</span><span class="p">.</span><span class="nf">loadState</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">state</span><span class="p">.</span><span class="nx">LastFull</span> <span class="o">==</span> <span class="s">""</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"No full backup exists, creating one first..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">m</span><span class="p">.</span><span class="nf">CreateFullBackup</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">timestamp</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Format</span><span class="p">(</span><span class="s">"20060102-150405"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">backupPath</span> <span class="o">:=</span> <span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nx">backupDir</span><span class="p">,</span> <span class="s">"incremental"</span><span class="p">,</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"incr-%s.backup"</span><span class="p">,</span> <span class="nx">timestamp</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">rows</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">m</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">QueryContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="s">`
</span></span></span><span class="line"><span class="cl"><span class="s"> CALL geode.backup.incremental($1, $2, {compression: 'gzip'})
</span></span></span><span class="line"><span class="cl"><span class="s"> `</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="nx">state</span><span class="p">.</span><span class="nx">LastLSN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">rows</span><span class="p">.</span><span class="nf">Next</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">changes</span> <span class="kt">int64</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">endLSN</span> <span class="kt">int64</span>
</span></span><span class="line"><span class="cl"> <span class="nx">rows</span><span class="p">.</span><span class="nf">Scan</span><span class="p">(</span><span class="o">&</span><span class="nx">changes</span><span class="p">,</span> <span class="o">&</span><span class="nx">endLSN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">changes</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">os</span><span class="p">.</span><span class="nf">Remove</span><span class="p">(</span><span class="nx">backupPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"No changes since last backup"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">state</span><span class="p">.</span><span class="nx">LastLSN</span> <span class="p">=</span> <span class="nx">endLSN</span>
</span></span><span class="line"><span class="cl"> <span class="nx">m</span><span class="p">.</span><span class="nf">saveState</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"Incremental backup: %s (changes: %d, LSN: %d)"</span><span class="p">,</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="nx">changes</span><span class="p">,</span> <span class="nx">endLSN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">backupPath</span><span class="p">,</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"incremental backup failed"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">db</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">sql</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">"geode"</span><span class="p">,</span> <span class="s">"localhost:3141"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">db</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">ctx</span> <span class="o">:=</span> <span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">manager</span> <span class="o">:=</span> <span class="nf">NewIncrementalBackupManager</span><span class="p">(</span><span class="s">"/backups/geode"</span><span class="p">,</span> <span class="nx">db</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// Create incremental backup
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">manager</span><span class="p">.</span><span class="nf">CreateIncrementalBackup</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Fatalf</span><span class="p">(</span><span class="s">"Backup failed: %v"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
</div></div>
</div>
<h3 id="point-in-time-recovery" class="position-relative d-flex align-items-center group">
<span>Point-in-Time Recovery</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="point-in-time-recovery"
aria-haspopup="dialog"
aria-label="Share link: Point-in-Time Recovery">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="understanding-pitr" class="position-relative d-flex align-items-center group">
<span>Understanding PITR</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="understanding-pitr"
aria-haspopup="dialog"
aria-label="Share link: Understanding PITR">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Point-in-Time Recovery allows you to restore the database to any specific moment.</p>
<p><strong>Requirements</strong>:</p>
<ul>
<li>Full backup as a base</li>
<li>Continuous WAL (Write-Ahead Log) archiving</li>
<li>WAL files stored safely</li>
</ul>
<h4 id="configuring-wal-archiving" class="position-relative d-flex align-items-center group">
<span>Configuring WAL Archiving</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="configuring-wal-archiving"
aria-haspopup="dialog"
aria-label="Share link: Configuring WAL Archiving">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p><strong>geode.conf</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">wal</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">archive_enabled</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="nx">archive_command</span> <span class="p">=</span> <span class="s2">"cp %p /backups/wal/%f"</span>
</span></span><span class="line"><span class="cl"><span class="nx">archive_timeout</span> <span class="p">=</span> <span class="mi">60</span> <span class="c"># seconds</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">recovery</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">restore_command</span> <span class="p">=</span> <span class="s2">"cp /backups/wal/%f %p"</span>
</span></span></code></pre></div>
<h4 id="performing-point-in-time-recovery" class="position-relative d-flex align-items-center group">
<span>Performing Point-in-Time Recovery</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="performing-point-in-time-recovery"
aria-haspopup="dialog"
aria-label="Share link: Performing Point-in-Time Recovery">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Restore to specific timestamp</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/full/geode-full-20260125.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --wal-dir /backups/wal <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --target-time <span class="s2">"2026-01-28T14:30:00Z"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restore to specific transaction</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/full/geode-full-20260125.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --wal-dir /backups/wal <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --target-lsn <span class="m">12345678</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data
</span></span></code></pre></div><div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883839918913" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883839918913-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883839918913-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883839918913-tab-0"
aria-selected="true"
>
Python
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883839918913-content"><div
class="tab-pane fade show active"
id="tabs-1774880883839918913-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883839918913-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">point_in_time_recovery</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">wal_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">target_time</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">output_dir</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Restore database to a specific point in time."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Starting point-in-time recovery..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Base backup: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Target time: </span><span class="si">{</span><span class="n">target_time</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Initiate PITR</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.restore.point_in_time($backup, $wal_dir, $target, $output, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> verify: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> create_recovery_conf: true
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"backup"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"wal_dir"</span><span class="p">:</span> <span class="n">wal_dir</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"target"</span><span class="p">:</span> <span class="n">target_time</span><span class="o">.</span><span class="n">isoformat</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"output"</span><span class="p">:</span> <span class="n">output_dir</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">info</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Recovery complete:"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Restored to: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'restored_to'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" WAL files applied: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'wal_files_applied'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Transactions recovered: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'transactions_recovered'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Restore to 2:30 PM today</span>
</span></span><span class="line"><span class="cl"> <span class="n">target</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">2026</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">28</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">point_in_time_recovery</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span><span class="o">=</span><span class="s2">"/backups/full/geode-full-20260125.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">wal_dir</span><span class="o">=</span><span class="s2">"/backups/wal"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">target_time</span><span class="o">=</span><span class="n">target</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">output_dir</span><span class="o">=</span><span class="s2">"/var/lib/geode/data-recovered"</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
</div></div>
</div>
<h3 id="backup-verification" class="position-relative d-flex align-items-center group">
<span>Backup Verification</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="backup-verification"
aria-haspopup="dialog"
aria-label="Share link: Backup Verification">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="automatic-verification" class="position-relative d-flex align-items-center group">
<span>Automatic Verification</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="automatic-verification"
aria-haspopup="dialog"
aria-label="Share link: Automatic Verification">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Verify backup integrity</span>
</span></span><span class="line"><span class="cl">geode backup verify /backups/geode-20260128.backup
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify with detailed output</span>
</span></span><span class="line"><span class="cl">geode backup verify <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/geode-20260128.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --check-checksums <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --check-consistency <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --verbose
</span></span></code></pre></div>
<h4 id="programmatic-verification" class="position-relative d-flex align-items-center group">
<span>Programmatic Verification</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="programmatic-verification"
aria-haspopup="dialog"
aria-label="Share link: Programmatic Verification">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883845372487" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883845372487-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883845372487-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883845372487-tab-0"
aria-selected="true"
>
Python
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883845372487-content"><div
class="tab-pane fade show active"
id="tabs-1774880883845372487-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883845372487-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">verify_backup</span><span class="p">(</span><span class="n">backup_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Comprehensively verify a backup file."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Verifying backup: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Basic integrity check</span>
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.backup.verify($path, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> check_checksums: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> check_consistency: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> check_indexes: true
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Verification failed: No result"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">info</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">checks</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"File integrity"</span><span class="p">:</span> <span class="n">info</span><span class="p">[</span><span class="s1">'file_valid'</span><span class="p">]</span><span class="o">.</span><span class="n">as_bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"Checksum match"</span><span class="p">:</span> <span class="n">info</span><span class="p">[</span><span class="s1">'checksum_valid'</span><span class="p">]</span><span class="o">.</span><span class="n">as_bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"Data consistency"</span><span class="p">:</span> <span class="n">info</span><span class="p">[</span><span class="s1">'data_consistent'</span><span class="p">]</span><span class="o">.</span><span class="n">as_bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"Index integrity"</span><span class="p">:</span> <span class="n">info</span><span class="p">[</span><span class="s1">'indexes_valid'</span><span class="p">]</span><span class="o">.</span><span class="n">as_bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">all_passed</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">check_name</span><span class="p">,</span> <span class="n">passed</span> <span class="ow">in</span> <span class="n">checks</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">status</span> <span class="o">=</span> <span class="s2">"PASS"</span> <span class="k">if</span> <span class="n">passed</span> <span class="k">else</span> <span class="s2">"FAIL"</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">check_name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">passed</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">all_passed</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">all_passed</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Backup verification: PASSED"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Checksum: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'checksum'</span><span class="p">]</span><span class="o">.</span><span class="n">as_string</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Node count: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'node_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Relationship count: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'relationship_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Backup verification: FAILED"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">all_passed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">verify_all_backups</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Verify all backups in a directory."""</span>
</span></span><span class="line"><span class="cl"> <span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.backup'</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">valid</span> <span class="o">=</span> <span class="k">await</span> <span class="n">verify_backup</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">filename</span><span class="p">,</span> <span class="n">valid</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"="</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"SUMMARY"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"="</span> <span class="o">*</span> <span class="mi">50</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">filename</span><span class="p">,</span> <span class="n">valid</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">status</span> <span class="o">=</span> <span class="s2">"OK"</span> <span class="k">if</span> <span class="n">valid</span> <span class="k">else</span> <span class="s2">"FAILED"</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">verify_all_backups</span><span class="p">(</span><span class="s2">"/backups/full"</span><span class="p">))</span>
</span></span></code></pre></div>
</div></div>
</div>
<h4 id="test-restores" class="position-relative d-flex align-items-center group">
<span>Test Restores</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="test-restores"
aria-haspopup="dialog"
aria-label="Share link: Test Restores">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><p>Regularly test your backups by performing test restores:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1"># Test restore script</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">BACKUP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"><span class="nv">TEST_DIR</span><span class="o">=</span><span class="s2">"/tmp/geode-test-restore"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Clean up previous test</span>
</span></span><span class="line"><span class="cl">rm -rf <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restore to test directory</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --no-start
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify data</span>
</span></span><span class="line"><span class="cl">geode verify <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Start test instance</span>
</span></span><span class="line"><span class="cl">geode serve <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --data-dir <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --port <span class="m">3142</span> <span class="p">&</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">GEODE_PID</span><span class="o">=</span><span class="nv">$!</span>
</span></span><span class="line"><span class="cl">sleep <span class="m">5</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Run verification queries</span>
</span></span><span class="line"><span class="cl">geode shell --port <span class="m">3142</span> -c <span class="s2">"MATCH (n) RETURN count(n)"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Stop test instance</span>
</span></span><span class="line"><span class="cl"><span class="nb">kill</span> <span class="si">${</span><span class="nv">GEODE_PID</span><span class="si">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Clean up</span>
</span></span><span class="line"><span class="cl">rm -rf <span class="s2">"</span><span class="si">${</span><span class="nv">TEST_DIR</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">"Test restore completed successfully"</span>
</span></span></code></pre></div>
<h3 id="restore-procedures" class="position-relative d-flex align-items-center group">
<span>Restore Procedures</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="restore-procedures"
aria-haspopup="dialog"
aria-label="Share link: Restore Procedures">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="full-restore" class="position-relative d-flex align-items-center group">
<span>Full Restore</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="full-restore"
aria-haspopup="dialog"
aria-label="Share link: Full Restore">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Stop Geode</span>
</span></span><span class="line"><span class="cl">systemctl stop geode
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restore from backup</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/geode-full-20260128.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --overwrite
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify restored data</span>
</span></span><span class="line"><span class="cl">geode verify /var/lib/geode/data
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Start Geode</span>
</span></span><span class="line"><span class="cl">systemctl start geode
</span></span></code></pre></div>
<h4 id="restore-from-incremental-backups" class="position-relative d-flex align-items-center group">
<span>Restore from Incremental Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="restore-from-incremental-backups"
aria-haspopup="dialog"
aria-label="Share link: Restore from Incremental Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Restore full backup first</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/full/geode-full-20260125.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Apply incremental backups in order</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/incremental/geode-incr-20260126.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --incremental
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/incremental/geode-incr-20260127.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --incremental
</span></span></code></pre></div>
<h4 id="programmatic-restore" class="position-relative d-flex align-items-center group">
<span>Programmatic Restore</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="programmatic-restore"
aria-haspopup="dialog"
aria-label="Share link: Programmatic Restore">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883853612658" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883853612658-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883853612658-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883853612658-tab-0"
aria-selected="true"
>
Python
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883853612658-content"><div
class="tab-pane fade show active"
id="tabs-1774880883853612658-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883853612658-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">restore_database</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">output_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">incremental_backups</span><span class="p">:</span> <span class="nb">list</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl"><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Restore database from backup files."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Ensure output directory exists</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">output_dir</span><span class="p">,</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Restore full backup</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Restoring full backup: </span><span class="si">{</span><span class="n">backup_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.restore.full($backup, $output, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> verify: true,
</span></span></span><span class="line"><span class="cl"><span class="s2"> overwrite: true
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"backup"</span><span class="p">:</span> <span class="n">backup_path</span><span class="p">,</span> <span class="s2">"output"</span><span class="p">:</span> <span class="n">output_dir</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">info</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Nodes restored: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'node_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Relationships restored: </span><span class="si">{</span><span class="n">info</span><span class="p">[</span><span class="s1">'relationship_count'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Apply incremental backups</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">incremental_backups</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">incr_backup</span> <span class="ow">in</span> <span class="n">incremental_backups</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Applying incremental: </span><span class="si">{</span><span class="n">incr_backup</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">result</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""CALL geode.restore.incremental($backup, $output, {
</span></span></span><span class="line"><span class="cl"><span class="s2"> verify: true
</span></span></span><span class="line"><span class="cl"><span class="s2"> })"""</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"backup"</span><span class="p">:</span> <span class="n">incr_backup</span><span class="p">,</span> <span class="s2">"output"</span><span class="p">:</span> <span class="n">output_dir</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">changes</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">rows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'changes_applied'</span><span class="p">]</span><span class="o">.</span><span class="n">as_int</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" Changes applied: </span><span class="si">{</span><span class="n">changes</span><span class="si">:</span><span class="s2">,</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Restore complete. Data directory: </span><span class="si">{</span><span class="n">output_dir</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">restore_database</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_path</span><span class="o">=</span><span class="s2">"/backups/full/geode-full-20260125.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">output_dir</span><span class="o">=</span><span class="s2">"/var/lib/geode/data-restored"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">incremental_backups</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"/backups/incremental/geode-incr-20260126.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"/backups/incremental/geode-incr-20260127.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"/backups/incremental/geode-incr-20260128.backup"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
</div></div>
</div>
<h3 id="disaster-recovery-planning" class="position-relative d-flex align-items-center group">
<span>Disaster Recovery Planning</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="disaster-recovery-planning"
aria-haspopup="dialog"
aria-label="Share link: Disaster Recovery Planning">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="recovery-time-objective-rto-and-recovery-point-objective-rpo" class="position-relative d-flex align-items-center group">
<span>Recovery Time Objective (RTO) and Recovery Point Objective (RPO)</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="recovery-time-objective-rto-and-recovery-point-objective-rpo"
aria-haspopup="dialog"
aria-label="Share link: Recovery Time Objective (RTO) and Recovery Point Objective (RPO)">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><table>
<thead>
<tr>
<th>Strategy</th>
<th>RTO</th>
<th>RPO</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>Standby replica</td>
<td>Minutes</td>
<td>Seconds</td>
<td>High</td>
</tr>
<tr>
<td>Continuous backup</td>
<td>Hours</td>
<td>Minutes</td>
<td>Medium</td>
</tr>
<tr>
<td>Daily backup</td>
<td>Hours-Days</td>
<td>24 hours</td>
<td>Low</td>
</tr>
</tbody>
</table>
<h4 id="disaster-recovery-runbook" class="position-relative d-flex align-items-center group">
<span>Disaster Recovery Runbook</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="disaster-recovery-runbook"
aria-haspopup="dialog"
aria-label="Share link: Disaster Recovery Runbook">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># Geode Disaster Recovery Runbook
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="gu">## 1. Assess the Situation
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Identify the nature of the failure
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Determine data loss extent
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Notify stakeholders
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 2. Activate Recovery
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Access backup storage
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Identify latest valid backup
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Prepare recovery environment
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 3. Restore Database
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Deploy new Geode instance
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Restore from backup
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Apply incremental/WAL files
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Verify data integrity
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 4. Validate Recovery
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Run consistency checks
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Execute test queries
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Verify application connectivity
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 5. Resume Operations
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Update DNS/load balancer
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Monitor performance
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Document incident
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 6. Post-Incident
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">- [ ]</span> Root cause analysis
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Update procedures
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Test improvements
</span></span></code></pre></div>
<h4 id="multi-region-backup-strategy" class="position-relative d-flex align-items-center group">
<span>Multi-Region Backup Strategy</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="multi-region-backup-strategy"
aria-haspopup="dialog"
aria-label="Share link: Multi-Region Backup Strategy">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="docs-tabs mb-4">
<ul class="nav nav-tabs" id="tabs-1774880883859253796" role="tablist"><li class="nav-item" role="presentation">
<button
class="nav-link active"
id="tabs-1774880883859253796-tab-0-tab"
data-bs-toggle="tab"
data-bs-target="#tabs-1774880883859253796-tab-0"
type="button"
role="tab"
aria-controls="tabs-1774880883859253796-tab-0"
aria-selected="true"
>
Python
</button>
</li></ul>
<div class="tab-content border border-top-0 rounded-bottom p-3" id="tabs-1774880883859253796-content"><div
class="tab-pane fade show active"
id="tabs-1774880883859253796-tab-0"
role="tabpanel"
aria-labelledby="tabs-1774880883859253796-tab-0-tab"
>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MultiRegionBackupManager</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span> <span class="o">=</span> <span class="s2">"us-east-1"</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">backup_regions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"us-west-2"</span><span class="p">,</span> <span class="s2">"eu-west-1"</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">s3_clients</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">region</span><span class="p">:</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s1">'s3'</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="n">region</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">region</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">backup_regions</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">create_and_replicate_backup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Create backup and replicate to multiple regions."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">timestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">local_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"/tmp/geode-backup-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"> <span class="n">s3_key</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"backups/geode/full-</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Create local backup</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"Creating backup..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CALL geode.backup.full($path, {compression: 'gzip'})"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">local_path</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Upload to primary region</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Uploading to </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="si">}</span><span class="s2">..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">s3_clients</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="p">]</span><span class="o">.</span><span class="n">upload_file</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">local_path</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"geode-backups-</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">s3_key</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Replicate to backup regions</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">region</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">backup_regions</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Replicating to </span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">..."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Copy from primary to backup region</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">s3_clients</span><span class="p">[</span><span class="n">region</span><span class="p">]</span><span class="o">.</span><span class="n">copy_object</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">CopySource</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Bucket'</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"geode-backups-</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Key'</span><span class="p">:</span> <span class="n">s3_key</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="n">Bucket</span><span class="o">=</span><span class="sa">f</span><span class="s2">"geode-backups-</span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Key</span><span class="o">=</span><span class="n">s3_key</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Backup replicated to </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">backup_regions</span><span class="p">)</span><span class="si">}</span><span class="s2"> regions"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Clean up local file</span>
</span></span><span class="line"><span class="cl"> <span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">local_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">def</span> <span class="nf">restore_from_nearest_region</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">target_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Restore from the nearest available region."""</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Check backup availability in each region</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">region</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">primary_region</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">backup_regions</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">bucket</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"geode-backups-</span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"> <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">s3_clients</span><span class="p">[</span><span class="n">region</span><span class="p">]</span><span class="o">.</span><span class="n">list_objects_v2</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">Bucket</span><span class="o">=</span><span class="n">bucket</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Prefix</span><span class="o">=</span><span class="s2">"backups/geode/full-"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">MaxKeys</span><span class="o">=</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'Contents'</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">response</span><span class="p">[</span><span class="s1">'Contents'</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="s1">'LastModified'</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl"> <span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Restoring from </span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">latest</span><span class="p">[</span><span class="s1">'Key'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Download backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">local_path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"/tmp/restore-</span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">s3_clients</span><span class="p">[</span><span class="n">region</span><span class="p">]</span><span class="o">.</span><span class="n">download_file</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">bucket</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest</span><span class="p">[</span><span class="s1">'Key'</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="n">local_path</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Restore</span>
</span></span><span class="line"><span class="cl"> <span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3141</span><span class="p">,</span> <span class="n">skip_verify</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">async</span> <span class="k">with</span> <span class="n">client</span><span class="o">.</span><span class="n">connection</span><span class="p">()</span> <span class="k">as</span> <span class="n">conn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"CALL geode.restore.full($path, $output)"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span><span class="s2">"path"</span><span class="p">:</span> <span class="n">local_path</span><span class="p">,</span> <span class="s2">"output"</span><span class="p">:</span> <span class="n">target_dir</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Restore complete from </span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Region </span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2"> unavailable: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"No backup available in any region!"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="n">manager</span> <span class="o">=</span> <span class="n">MultiRegionBackupManager</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Create and replicate backup</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">manager</span><span class="o">.</span><span class="n">create_and_replicate_backup</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div>
</div></div>
</div>
<h3 id="automated-backup-scheduling" class="position-relative d-flex align-items-center group">
<span>Automated Backup Scheduling</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="automated-backup-scheduling"
aria-haspopup="dialog"
aria-label="Share link: Automated Backup Scheduling">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="cron-based-scheduling" class="position-relative d-flex align-items-center group">
<span>Cron-Based Scheduling</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="cron-based-scheduling"
aria-haspopup="dialog"
aria-label="Share link: Cron-Based Scheduling">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># /etc/cron.d/geode-backup</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Full backup every Sunday at 2 AM</span>
</span></span><span class="line"><span class="cl"><span class="m">0</span> <span class="m">2</span> * * <span class="m">0</span> geode /usr/local/bin/geode-full-backup.sh >> /var/log/geode-backup.log 2><span class="p">&</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Incremental backup every day at 2 AM (except Sunday)</span>
</span></span><span class="line"><span class="cl"><span class="m">0</span> <span class="m">2</span> * * 1-6 geode /usr/local/bin/geode-incr-backup.sh >> /var/log/geode-backup.log 2><span class="p">&</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># WAL archiving check every 5 minutes</span>
</span></span><span class="line"><span class="cl">*/5 * * * * geode /usr/local/bin/geode-wal-check.sh >> /var/log/geode-wal.log 2><span class="p">&</span><span class="m">1</span>
</span></span></code></pre></div>
<h4 id="systemd-timer" class="position-relative d-flex align-items-center group">
<span>Systemd Timer</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="systemd-timer"
aria-haspopup="dialog"
aria-label="Share link: Systemd Timer">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># /etc/systemd/system/geode-backup.service</span>
</span></span><span class="line"><span class="cl"><span class="k">[Unit]</span>
</span></span><span class="line"><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Geode Database Backup</span>
</span></span><span class="line"><span class="cl"><span class="na">After</span><span class="o">=</span><span class="s">geode.service</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="cl"><span class="na">Type</span><span class="o">=</span><span class="s">oneshot</span>
</span></span><span class="line"><span class="cl"><span class="na">User</span><span class="o">=</span><span class="s">geode</span>
</span></span><span class="line"><span class="cl"><span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/local/bin/geode-backup.sh</span>
</span></span><span class="line"><span class="cl"><span class="na">StandardOutput</span><span class="o">=</span><span class="s">journal</span>
</span></span><span class="line"><span class="cl"><span class="na">StandardError</span><span class="o">=</span><span class="s">journal</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># /etc/systemd/system/geode-backup.timer</span>
</span></span><span class="line"><span class="cl"><span class="k">[Unit]</span>
</span></span><span class="line"><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Daily Geode Backup Timer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Timer]</span>
</span></span><span class="line"><span class="cl"><span class="na">OnCalendar</span><span class="o">=</span><span class="s">*-*-* 02:00:00</span>
</span></span><span class="line"><span class="cl"><span class="na">Persistent</span><span class="o">=</span><span class="s">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Install]</span>
</span></span><span class="line"><span class="cl"><span class="na">WantedBy</span><span class="o">=</span><span class="s">timers.target</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Enable timer</span>
</span></span><span class="line"><span class="cl">systemctl <span class="nb">enable</span> geode-backup.timer
</span></span><span class="line"><span class="cl">systemctl start geode-backup.timer
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Check timer status</span>
</span></span><span class="line"><span class="cl">systemctl list-timers <span class="p">|</span> grep geode
</span></span></code></pre></div>
<h4 id="comprehensive-backup-script" class="position-relative d-flex align-items-center group">
<span>Comprehensive Backup Script</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="comprehensive-backup-script"
aria-haspopup="dialog"
aria-label="Share link: Comprehensive Backup Script">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1"># /usr/local/bin/geode-backup.sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Configuration</span>
</span></span><span class="line"><span class="cl"><span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">"/backups/geode"</span>
</span></span><span class="line"><span class="cl"><span class="nv">FULL_DIR</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">/full"</span>
</span></span><span class="line"><span class="cl"><span class="nv">INCR_DIR</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">/incremental"</span>
</span></span><span class="line"><span class="cl"><span class="nv">WAL_DIR</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">/wal"</span>
</span></span><span class="line"><span class="cl"><span class="nv">STATE_FILE</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_DIR</span><span class="si">}</span><span class="s2">/backup_state.json"</span>
</span></span><span class="line"><span class="cl"><span class="nv">RETENTION_DAYS</span><span class="o">=</span><span class="m">30</span>
</span></span><span class="line"><span class="cl"><span class="nv">FULL_BACKUP_DAY</span><span class="o">=</span><span class="m">0</span> <span class="c1"># Sunday</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Logging</span>
</span></span><span class="line"><span class="cl">log<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"[</span><span class="k">$(</span>date <span class="s1">'+%Y-%m-%d %H:%M:%S'</span><span class="k">)</span><span class="s2">] </span><span class="nv">$1</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create directories</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">"</span><span class="si">${</span><span class="nv">FULL_DIR</span><span class="si">}</span><span class="s2">"</span> <span class="s2">"</span><span class="si">${</span><span class="nv">INCR_DIR</span><span class="si">}</span><span class="s2">"</span> <span class="s2">"</span><span class="si">${</span><span class="nv">WAL_DIR</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Determine backup type</span>
</span></span><span class="line"><span class="cl"><span class="nv">DAY_OF_WEEK</span><span class="o">=</span><span class="k">$(</span>date +%w<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">TIMESTAMP</span><span class="o">=</span><span class="k">$(</span>date +%Y%m%d-%H%M%S<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="si">${</span><span class="nv">DAY_OF_WEEK</span><span class="si">}</span><span class="s2">"</span> -eq <span class="s2">"</span><span class="si">${</span><span class="nv">FULL_BACKUP_DAY</span><span class="si">}</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl"> <span class="nv">BACKUP_TYPE</span><span class="o">=</span><span class="s2">"full"</span>
</span></span><span class="line"><span class="cl"> <span class="nv">BACKUP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">FULL_DIR</span><span class="si">}</span><span class="s2">/geode-full-</span><span class="si">${</span><span class="nv">TIMESTAMP</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"> <span class="nv">BACKUP_TYPE</span><span class="o">=</span><span class="s2">"incremental"</span>
</span></span><span class="line"><span class="cl"> <span class="nv">BACKUP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">INCR_DIR</span><span class="si">}</span><span class="s2">/geode-incr-</span><span class="si">${</span><span class="nv">TIMESTAMP</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">log <span class="s2">"Starting </span><span class="si">${</span><span class="nv">BACKUP_TYPE</span><span class="si">}</span><span class="s2"> backup"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create backup</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_TYPE</span><span class="si">}</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"full"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl"> geode backup full <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compress gzip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --verify
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Update state with new full backup</span>
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"{\"last_full\": \"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">\"}"</span> > <span class="s2">"</span><span class="si">${</span><span class="nv">STATE_FILE</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Read last full backup from state</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="o">[</span> -f <span class="s2">"</span><span class="si">${</span><span class="nv">STATE_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl"> <span class="nv">LAST_FULL</span><span class="o">=</span><span class="k">$(</span>jq -r <span class="s1">'.last_full'</span> <span class="s2">"</span><span class="si">${</span><span class="nv">STATE_FILE</span><span class="si">}</span><span class="s2">"</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span>
</span></span><span class="line"><span class="cl"> log <span class="s2">"No state file found. Creating full backup instead."</span>
</span></span><span class="line"><span class="cl"> <span class="nv">BACKUP_FILE</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">FULL_DIR</span><span class="si">}</span><span class="s2">/geode-full-</span><span class="si">${</span><span class="nv">TIMESTAMP</span><span class="si">}</span><span class="s2">.backup"</span>
</span></span><span class="line"><span class="cl"> geode backup full --output <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> --compress gzip --verify
</span></span><span class="line"><span class="cl"> <span class="nb">echo</span> <span class="s2">"{\"last_full\": \"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">\"}"</span> > <span class="s2">"</span><span class="si">${</span><span class="nv">STATE_FILE</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"> <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"> <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> geode backup incremental <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --base <span class="s2">"</span><span class="si">${</span><span class="nv">LAST_FULL</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --compress gzip <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --verify
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verify backup</span>
</span></span><span class="line"><span class="cl">log <span class="s2">"Verifying backup..."</span>
</span></span><span class="line"><span class="cl">geode backup verify <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Get backup size</span>
</span></span><span class="line"><span class="cl"><span class="nv">SIZE</span><span class="o">=</span><span class="k">$(</span>du -h <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="p">|</span> cut -f1<span class="k">)</span>
</span></span><span class="line"><span class="cl">log <span class="s2">"Backup complete: </span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2"> (</span><span class="si">${</span><span class="nv">SIZE</span><span class="si">}</span><span class="s2">)"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Clean up old backups</span>
</span></span><span class="line"><span class="cl">log <span class="s2">"Cleaning up backups older than </span><span class="si">${</span><span class="nv">RETENTION_DAYS</span><span class="si">}</span><span class="s2"> days..."</span>
</span></span><span class="line"><span class="cl">find <span class="s2">"</span><span class="si">${</span><span class="nv">FULL_DIR</span><span class="si">}</span><span class="s2">"</span> -name <span class="s2">"*.backup"</span> -mtime +<span class="si">${</span><span class="nv">RETENTION_DAYS</span><span class="si">}</span> -delete
</span></span><span class="line"><span class="cl">find <span class="s2">"</span><span class="si">${</span><span class="nv">INCR_DIR</span><span class="si">}</span><span class="s2">"</span> -name <span class="s2">"*.backup"</span> -mtime +<span class="si">${</span><span class="nv">RETENTION_DAYS</span><span class="si">}</span> -delete
</span></span><span class="line"><span class="cl">find <span class="s2">"</span><span class="si">${</span><span class="nv">WAL_DIR</span><span class="si">}</span><span class="s2">"</span> -name <span class="s2">"*.wal"</span> -mtime +<span class="si">${</span><span class="nv">RETENTION_DAYS</span><span class="si">}</span> -delete
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Upload to remote storage (optional)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -n <span class="s2">"</span><span class="si">${</span><span class="nv">S3_BUCKET</span><span class="k">:-</span><span class="si">}</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl"> log <span class="s2">"Uploading to S3..."</span>
</span></span><span class="line"><span class="cl"> aws s3 cp <span class="s2">"</span><span class="si">${</span><span class="nv">BACKUP_FILE</span><span class="si">}</span><span class="s2">"</span> <span class="s2">"s3://</span><span class="si">${</span><span class="nv">S3_BUCKET</span><span class="si">}</span><span class="s2">/backups/geode/"</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">log <span class="s2">"Backup job completed successfully"</span>
</span></span></code></pre></div>
<h3 id="monitoring-backups" class="position-relative d-flex align-items-center group">
<span>Monitoring Backups</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="monitoring-backups"
aria-haspopup="dialog"
aria-label="Share link: Monitoring Backups">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="backup-health-checks" class="position-relative d-flex align-items-center group">
<span>Backup Health Checks</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="backup-health-checks"
aria-haspopup="dialog"
aria-label="Share link: Backup Health Checks">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">geode_client</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">check_backup_health</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Check backup health and alert on issues."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check for recent full backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">full_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"full"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">full_dir</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">full_backups</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">([</span>
</span></span><span class="line"><span class="cl"> <span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">full_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.backup'</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">full_backups</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"No full backups found"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest_full</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">full_dir</span><span class="p">,</span> <span class="n">full_backups</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"> <span class="n">mtime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span><span class="n">latest_full</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="n">age_days</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">mtime</span><span class="p">)</span><span class="o">.</span><span class="n">days</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">age_days</span> <span class="o">></span> <span class="mi">7</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Latest full backup is </span><span class="si">{</span><span class="n">age_days</span><span class="si">}</span><span class="s2"> days old"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check for recent incremental backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">incr_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"incremental"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">incr_dir</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">incr_backups</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">([</span>
</span></span><span class="line"><span class="cl"> <span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">incr_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.backup'</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">incr_backups</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest_incr</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">incr_dir</span><span class="p">,</span> <span class="n">incr_backups</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"> <span class="n">mtime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span><span class="n">latest_incr</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="n">age_hours</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">mtime</span><span class="p">)</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">()</span> <span class="o">/</span> <span class="mi">3600</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">age_hours</span> <span class="o">></span> <span class="mi">25</span><span class="p">:</span> <span class="c1"># More than 25 hours</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Latest incremental is </span><span class="si">{</span><span class="n">age_hours</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2"> hours old"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check WAL archiving</span>
</span></span><span class="line"><span class="cl"> <span class="n">wal_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="s2">"wal"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">wal_dir</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">wal_files</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">wal_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.wal'</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">wal_files</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest_wal</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">wal_files</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">wal_dir</span><span class="p">,</span> <span class="n">f</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"> <span class="n">mtime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">wal_dir</span><span class="p">,</span> <span class="n">latest_wal</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"> <span class="n">age_minutes</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">mtime</span><span class="p">)</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">()</span> <span class="o">/</span> <span class="mi">60</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">age_minutes</span> <span class="o">></span> <span class="mi">10</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"WAL archiving may be delayed (</span><span class="si">{</span><span class="n">age_minutes</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2"> min)"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Check disk space</span>
</span></span><span class="line"><span class="cl"> <span class="n">statvfs</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">statvfs</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">free_gb</span> <span class="o">=</span> <span class="p">(</span><span class="n">statvfs</span><span class="o">.</span><span class="n">f_frsize</span> <span class="o">*</span> <span class="n">statvfs</span><span class="o">.</span><span class="n">f_bavail</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1024</span><span class="o">**</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">free_gb</span> <span class="o"><</span> <span class="mi">50</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">issues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Low disk space: </span><span class="si">{</span><span class="n">free_gb</span><span class="si">:</span><span class="s2">.1f</span><span class="si">}</span><span class="s2"> GB free"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Report</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">issues</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"BACKUP HEALTH CHECK: ISSUES FOUND"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">issue</span> <span class="ow">in</span> <span class="n">issues</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" - </span><span class="si">{</span><span class="n">issue</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl"> <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"BACKUP HEALTH CHECK: OK"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">check_backup_health</span><span class="p">(</span><span class="s2">"/backups/geode"</span><span class="p">))</span>
</span></span></code></pre></div>
<h4 id="prometheus-metrics" class="position-relative d-flex align-items-center group">
<span>Prometheus Metrics</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="prometheus-metrics"
aria-haspopup="dialog"
aria-label="Share link: Prometheus Metrics">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Expose backup metrics for Prometheus</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">prometheus_client</span> <span class="kn">import</span> <span class="n">Gauge</span><span class="p">,</span> <span class="n">Counter</span><span class="p">,</span> <span class="n">start_http_server</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Define metrics</span>
</span></span><span class="line"><span class="cl"><span class="n">backup_age_seconds</span> <span class="o">=</span> <span class="n">Gauge</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode_backup_age_seconds'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Age of the latest backup in seconds'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s1">'type'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">backup_size_bytes</span> <span class="o">=</span> <span class="n">Gauge</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode_backup_size_bytes'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Size of the latest backup in bytes'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s1">'type'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">backup_count</span> <span class="o">=</span> <span class="n">Gauge</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode_backup_count'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Number of backup files'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">[</span><span class="s1">'type'</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">backup_disk_free_bytes</span> <span class="o">=</span> <span class="n">Gauge</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'geode_backup_disk_free_bytes'</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s1">'Free disk space for backups'</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">update_metrics</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Update Prometheus metrics."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">backup_type</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">'full'</span><span class="p">,</span> <span class="s1">'incremental'</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl"> <span class="n">type_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">,</span> <span class="n">backup_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">type_dir</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">backups</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">type_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.backup'</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Count</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_count</span><span class="o">.</span><span class="n">labels</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="n">backup_type</span><span class="p">)</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">backups</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">backups</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Latest backup</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">backups</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">type_dir</span><span class="p">,</span> <span class="n">f</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"> <span class="n">latest_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">type_dir</span><span class="p">,</span> <span class="n">latest</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Age</span>
</span></span><span class="line"><span class="cl"> <span class="n">age</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">timestamp</span><span class="p">()</span> <span class="o">-</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span><span class="n">latest_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_age_seconds</span><span class="o">.</span><span class="n">labels</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="n">backup_type</span><span class="p">)</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">age</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Size</span>
</span></span><span class="line"><span class="cl"> <span class="n">size</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">latest_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_size_bytes</span><span class="o">.</span><span class="n">labels</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="n">backup_type</span><span class="p">)</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Disk space</span>
</span></span><span class="line"><span class="cl"> <span class="n">statvfs</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">statvfs</span><span class="p">(</span><span class="n">backup_dir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">free_bytes</span> <span class="o">=</span> <span class="n">statvfs</span><span class="o">.</span><span class="n">f_frsize</span> <span class="o">*</span> <span class="n">statvfs</span><span class="o">.</span><span class="n">f_bavail</span>
</span></span><span class="line"><span class="cl"> <span class="n">backup_disk_free_bytes</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">free_bytes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Start metrics server</span>
</span></span><span class="line"><span class="cl"><span class="n">start_http_server</span><span class="p">(</span><span class="mi">9090</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Update metrics periodically</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">update_metrics</span><span class="p">(</span><span class="s2">"/backups/geode"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
</span></span></code></pre></div>
<h3 id="best-practices" class="position-relative d-flex align-items-center group">
<span>Best Practices</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="best-practices"
aria-haspopup="dialog"
aria-label="Share link: Best Practices">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3>
<h4 id="backup-checklist" class="position-relative d-flex align-items-center group">
<span>Backup Checklist</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="backup-checklist"
aria-haspopup="dialog"
aria-label="Share link: Backup Checklist">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><ul>
<li><input disabled="" type="checkbox"> <strong>Regular full backups</strong> (weekly recommended)</li>
<li><input disabled="" type="checkbox"> <strong>Daily incremental backups</strong></li>
<li><input disabled="" type="checkbox"> <strong>WAL archiving enabled</strong> for point-in-time recovery</li>
<li><input disabled="" type="checkbox"> <strong>Backup verification</strong> after each backup</li>
<li><input disabled="" type="checkbox"> <strong>Test restores</strong> at least monthly</li>
<li><input disabled="" type="checkbox"> <strong>Off-site backup storage</strong> (different region/provider)</li>
<li><input disabled="" type="checkbox"> <strong>Encryption</strong> for backups containing sensitive data</li>
<li><input disabled="" type="checkbox"> <strong>Monitoring and alerting</strong> for backup failures</li>
<li><input disabled="" type="checkbox"> <strong>Documented recovery procedures</strong></li>
<li><input disabled="" type="checkbox"> <strong>Regular DR drills</strong></li>
</ul>
<h4 id="security-considerations" class="position-relative d-flex align-items-center group">
<span>Security Considerations</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="security-considerations"
aria-haspopup="dialog"
aria-label="Share link: Security Considerations">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Encrypt backup</span>
</span></span><span class="line"><span class="cl">geode backup create <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /backups/geode.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --encrypt <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --encryption-key-file /etc/geode/backup.key
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restore encrypted backup</span>
</span></span><span class="line"><span class="cl">geode restore <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --backup /backups/geode.backup <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --decrypt <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --encryption-key-file /etc/geode/backup.key <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span> --output /var/lib/geode/data
</span></span></code></pre></div>
<h3 id="next-steps" class="position-relative d-flex align-items-center group">
<span>Next Steps</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="next-steps"
aria-haspopup="dialog"
aria-label="Share link: Next Steps">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><ul>
<li><a
href="/guides/data-import/"
>Data Import Guide</a>
- Import data into Geode</li>
<li><a
href="/guides/data-export/"
>Data Export Guide</a>
- Export your data</li>
<li><a
href="/guides/high-availability/"
>High Availability Guide</a>
- Configure HA</li>
<li><a
href="/docs/performance/"
>Performance Guide</a>
- Optimize performance</li>
</ul>
<h3 id="resources" class="position-relative d-flex align-items-center group">
<span>Resources</span>
<button type="button"
class="h-share btn btn-link p-0 text-decoration-none link-secondary opacity-50 hover-opacity-100 transition-all ms-1"
data-share-target="resources"
aria-haspopup="dialog"
aria-label="Share link: Resources">
<i class="fa-sharp-duotone fa-solid fa-share-nodes" aria-hidden="true" style="font-size: 0.8em;"></i>
<span class="visually-hidden">Share link</span>
</button>
</h3><ul>
<li><a
href="/docs/reference/cli-and-api/"
>CLI Reference</a>
</li>
<li><a
href="/docs/configuration/"
>Configuration Reference</a>
</li>
<li><a
href="/docs/api-reference/"
>API Reference</a>
</li>
<li><a
href="https://forum.geodedb.com"
aria-label="Community Forum – opens in new window"
target="_blank" rel="noopener noreferrer"
>Community Forum
<span aria-hidden="true" class="external-icon">↗</span>
</a>
</li>
</ul>
<hr>
<p><strong>Questions?</strong> Discuss backup strategies in our <a
href="https://forum.geodedb.com"
aria-label="forum – opens in new window"
target="_blank" rel="noopener noreferrer"
>forum
<span aria-hidden="true" class="external-icon">↗</span>
</a>
.</p>
Backup and Restore Guide
Comprehensive guide to backing up and restoring Geode databases
18 min read