mirror of
https://github.com/boostorg/boostlook.git
synced 2026-02-25 16:22:12 +00:00
1280 lines
46 KiB
HTML
1280 lines
46 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
|
|
<style>html.fonts-loading{visibility:hidden;opacity:0}</style>
|
|
<script>document.documentElement.classList.add('fonts-loading');</script>
|
|
|
|
<link rel="preload" href="../_/font/NotoSansDisplay.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
|
|
<link rel="preload" href="../_/font/NotoSansDisplay-Italic.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
|
|
<link rel="preload" href="../_/font/MonaspaceNeon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
|
|
<link rel="preload" href="../_/font/MonaspaceXenon-Var.woff2" as="font" type="font/woff2" crossorigin="anonymous" />
|
|
|
|
<script>
|
|
(function() {
|
|
'use strict';
|
|
|
|
var revealed = false;
|
|
|
|
var reveal = function() {
|
|
if (revealed) return;
|
|
revealed = true;
|
|
document.documentElement.classList.remove('fonts-loading');
|
|
};
|
|
|
|
setTimeout(reveal, 3000);
|
|
|
|
if (!('FontFace' in window) || !('fonts' in document)) {
|
|
setTimeout(reveal, 100);
|
|
return;
|
|
}
|
|
|
|
var uiRoot = '../_';
|
|
var fonts = [
|
|
{
|
|
family: 'Noto Sans',
|
|
url: uiRoot + '/font/NotoSansDisplay.woff2',
|
|
descriptors: { style: 'normal', weight: '100 900', stretch: '62.5% 100%' }
|
|
},
|
|
{
|
|
family: 'Noto Sans',
|
|
url: uiRoot + '/font/NotoSansDisplay-Italic.woff2',
|
|
descriptors: { style: 'italic', weight: '100 900', stretch: '62.5% 100%' }
|
|
},
|
|
{
|
|
family: 'Monaspace Neon',
|
|
url: uiRoot + '/font/MonaspaceNeon-Var.woff2',
|
|
descriptors: { style: 'normal', weight: '400' }
|
|
},
|
|
{
|
|
family: 'Monaspace Xenon',
|
|
url: uiRoot + '/font/MonaspaceXenon-Var.woff2',
|
|
descriptors: { style: 'italic', weight: '400' }
|
|
}
|
|
];
|
|
|
|
var loadPromises = fonts.map(function(f) {
|
|
try {
|
|
var face = new FontFace(f.family, 'url("' + f.url + '")', f.descriptors);
|
|
return face.load().then(function(loaded) {
|
|
document.fonts.add(loaded);
|
|
return loaded;
|
|
}).catch(function() {
|
|
return null;
|
|
});
|
|
} catch (e) {
|
|
return Promise.resolve(null);
|
|
}
|
|
});
|
|
|
|
Promise.all(loadPromises)
|
|
.then(function() {
|
|
return document.fonts.ready;
|
|
})
|
|
.then(reveal)
|
|
.catch(reveal);
|
|
})();
|
|
</script> <title>High-Performance Database Engine :: Boost Site Docs</title>
|
|
<link rel="canonical" href="https://boost.revsys.dev/user-guide/task-database.html">
|
|
<link rel="prev" href="advanced-introduction.html">
|
|
<link rel="next" href="task-machine-learning.html">
|
|
<meta name="generator" content="Antora 3.1.14">
|
|
<link rel="stylesheet" href="../_/css/boostlook.css">
|
|
<link rel="stylesheet" href="../_/css/site.css">
|
|
<link rel="stylesheet" href="../_/css/vendor/tabs.css">
|
|
<script>
|
|
(function() {
|
|
if (window.self !== window.top) return;
|
|
var theme = localStorage.getItem('antora-theme');
|
|
if (!theme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
theme = 'dark';
|
|
}
|
|
if (theme === 'dark') document.documentElement.classList.add('dark');
|
|
})();
|
|
</script>
|
|
<script>var uiRootPath = '../_'</script>
|
|
<link rel="icon" href="../_/img/favicons/favicon.ico" type="image/x-icon">
|
|
<!-- Favicon configuration -->
|
|
<link rel="apple-touch-icon" sizes="180x180" href="../_/img/favicons/apple-touch-icon.png">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="../_/img/favicons/favicon-32x32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="../_/img/favicons/favicon-16x16.png">
|
|
<link rel="manifest" href="../_/img/favicons/site.webmanifest">
|
|
<link rel="shortcut icon" href="../_/img/favicons/favicon.ico">
|
|
</head>
|
|
<body class="article toc2 toc-left">
|
|
<div class="boostlook">
|
|
<script type="module">import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({"startOnLoad":true});</script> <div id="header">
|
|
<div id="toc" class="nav-container toc2" data-component="user-guide" data-version="">
|
|
<aside class="nav">
|
|
<button class="nav-close"></button>
|
|
<div class="panels">
|
|
<div class="nav-panel-menu is-active" data-panel="menu">
|
|
<nav class="nav-menu">
|
|
<div class="title-row">
|
|
<h3 class="title"><a href="index.html">User Guide</a></h3>
|
|
<button class="theme-toggle" aria-label="Toggle dark mode" title="Toggle theme" style="display:none">
|
|
<i class="fas fa-sun theme-icon-light"></i>
|
|
<i class="fas fa-moon theme-icon-dark"></i>
|
|
</button> </div>
|
|
<ul class="nav-list">
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="1">
|
|
<a class="nav-link" href="intro.html">Introduction</a>
|
|
</li>
|
|
<li class="" data-depth="1">
|
|
<a class="nav-link" href="getting-started.html">Getting Started</a>
|
|
</li>
|
|
<li class="" data-depth="1">
|
|
<a class="nav-link" href="explore-the-content.html">Explore the Content</a>
|
|
</li>
|
|
<li class="" data-depth="1">
|
|
<a class="nav-link" href="faq.html">FAQ</a>
|
|
</li>
|
|
<li class="" data-depth="1">
|
|
<a class="nav-link" href="building-with-cmake.html">Building with CMake</a>
|
|
</li>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">Common Scenarios</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="common-introduction.html">Introduction</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-finance.html">Finance</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-networking.html">Networking</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-ai-client.html">AI Client</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-simulation.html">Simulation</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-system.html">System</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="testing-debugging.html">Testing and Debugging</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-text-processing.html">Text Processing</a>
|
|
</li>
|
|
</ul>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">Advanced Scenarios</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="advanced-introduction.html">Introduction</a>
|
|
</li>
|
|
<li class=" is-current-page" data-depth="2">
|
|
<a class="nav-link" href="task-database.html">Database Engine</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-machine-learning.html">Machine Learning</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-metaprogramming.html">Metaprogramming</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-natural-language-parsing.html">Natural Language</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-parallel-computation.html">Parallel Computation</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-quantum-computing.html">Quantum Computing</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-aeronautical-engineering.html">Aeronautical Engineering</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="task-bio-tech-engineering.html">Bio-Tech Engineering</a>
|
|
</li>
|
|
</ul>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">Development</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="boost-macros.html">Macros</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="generic-programming.html">Generic Programming</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="exception-safety.html">Exception-Safety</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="counted-body.html">Counted Body</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="implementation-variations.html">Implementation Variations</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="reduce-dependencies.html">Reduce Dependencies</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="diagnostics.html">Diagnostics</a>
|
|
</li>
|
|
</ul>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">User Community</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="user-community-introduction.html">Introduction</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="reporting-issues.html">Reporting Issues</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="discussion-policy.html">Discussion Policy</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="bsl.html">The Boost Software License</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="release-process.html">Release Process</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="boost-history.html">History</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="in-memoriam-beman-dawes.html">In Memoriam: Beman Dawes</a>
|
|
</li>
|
|
</ul>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">Resources</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="resources.html">Resources</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="glossary.html">Glossary</a>
|
|
</li>
|
|
</ul>
|
|
<li class="" data-depth="1">
|
|
<span class="nav-text">Reference</span>
|
|
</li>
|
|
<ul class="nav-list">
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="library-naming.html">Library Names and Organization</a>
|
|
</li>
|
|
<li class="" data-depth="2">
|
|
<a class="nav-link" href="header-organization-compilation.html">Header Organization and Compiled Binaries</a>
|
|
</li>
|
|
</ul>
|
|
</ul>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div> <div id="content">
|
|
<article class="doc max-width-reset">
|
|
<div class="toolbar" role="navigation">
|
|
<button class="nav-toggle"></button>
|
|
<nav class="breadcrumbs" aria-label="breadcrumbs">
|
|
<ul>
|
|
<li>
|
|
<a href="index.html" aria-label="Home: User Guide">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" viewBox="0 -960 960 960" fill="#000000" aria-hidden="true"><path d="M160-120v-480l320-240 320 240v480H560v-280H400v280H160Z"/></svg>
|
|
</a>
|
|
</li>
|
|
<li>Advanced Scenarios</li>
|
|
<li><a href="task-database.html">Database Engine</a></li>
|
|
</ul>
|
|
</nav>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="advanced-introduction.html">
|
|
<span class="material-symbols-outlined" title="Previous: Introduction">arrow_back</span>
|
|
</a>
|
|
<a class="disabled" accesskey="u" aria-disabled="true" tabindex="-1">
|
|
<span class="material-symbols-outlined" title="Up:">arrow_upward</span>
|
|
</a>
|
|
<a accesskey="n" href="task-machine-learning.html">
|
|
<span class="material-symbols-outlined" title="Next: Machine Learning">arrow_forward</span>
|
|
</a>
|
|
</div></div>
|
|
<h1 class="page">High-Performance Database Engine</h1>
|
|
<div id="preamble">
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Creating a high-performance database application in C++ involves a range of tasks, including efficient data structures, shared and optimized memory management, safe message and network communication, persistent storage, and so much more. This section examines how to get started.</p>
|
|
</div>
|
|
<div class="ulist square">
|
|
<ul class="square">
|
|
<li>
|
|
<p><a href="#_libraries">Libraries</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_sample_database_engine_using_containers">Sample Database Engine using Containers</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_optimize_memory_allocation">Optimize Memory Allocation</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_use_persistent_shared_memory">Use Persistent Shared Memory</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_safely_allow_access_from_multiple_processes">Safely Allow Access from Multiple Processes</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_add_serialization_to_archive_the_database">Add Serialization to Archive the Database</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_next_steps">Next Steps</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#_see_also">See Also</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_libraries"><a class="anchor" href="#_libraries"></a>Libraries</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Here are some Boost libraries that might be useful when planning and building your database app:</p>
|
|
</div>
|
|
<div class="ulist circle">
|
|
<ul class="circle">
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/container">Boost.Container</a> : Provides STL-compatible containers, including stable vector, flat set/map and more. The containers provided by this library can offer performance benefits over their standard library equivalents, making them a good fit for a high-performance database application.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/pool">Boost.Pool</a> : This library is used for simple, fast memory allocation and can improve efficiency in some scenarios by managing memory in chunks.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/interprocess">Boost.Interprocess</a> : This library allows for shared memory communication and synchronization between processes. In a database context, this can be useful for inter-process communication (IPC) and shared memory databases.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/lockfree">Boost.Lockfree</a> : Provides lock-free data structures which could be useful in multi-threaded database applications where you want to avoid locking overhead.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/serialization">Boost.Serialization</a> : If you need to serialize objects for storage, <a href="https://www.boost.org/libs/serialization">Boost.Serialization</a> can be a useful tool. However, be aware that for many database applications, more specialized serialization formats (like Protocol Buffers, Thrift, etc.) might be more appropriate.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/asio">Boost.Asio</a> : Provides a consistent asynchronous model using a modern C++ approach for network and low-level I/O programming. It supports a variety of network protocols, which could be helpful if your database needs to communicate over a network.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/thread">Boost.Thread</a> : Provides a portable interface for multithreading, which can be crucial when creating a high-performance database that can handle multiple queries concurrently.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/fiber">Boost.Fiber</a> : Allows you to write code that works with fibers, which are user-space threads that can be used to write concurrent code. This can be useful in situations where you have many tasks that need to run concurrently but are I/O-bound rather than CPU-bound.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/polygon">Boost.Polygon</a> or <a href="https://www.boost.org/libs/geometry">Boost.Geometry</a> : For storing and querying spatial data, these libraries can provide the necessary data types and algorithms.</p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/libs/filesystem">Boost.Filesystem</a> : Provides a portable way of querying and manipulating paths, files, and directories.</p>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">Note</dt>
|
|
<dd>
|
|
<p>The code in this tutorial was written and tested using Microsoft Visual Studio (Visual C++ 2022, Console App project) with Boost version 1.88.0.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_sample_database_engine_using_containers"><a class="anchor" href="#_sample_database_engine_using_containers"></a>Sample Database Engine using Containers</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>A database engine requires efficient data structures for handling indexes, caches, and storage layouts. The <a href="https://www.boost.org/libs/container">Boost.Container</a> library provides drop-in replacements for standard containers like <code>std::vector</code>, <code>std::map</code>, and <code>std::unordered_map</code>, but optimized for memory efficiency and performance.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>In the following sample code, we will use in-memory indexing as the basis of a database engine. The <a href="https://www.boost.org/libs/container">Boost.Container</a> <code>flat_map</code> feature is used to store a sorted index for quick lookups, and the <code>stable_vector</code> feature to store persistent records with stable pointers. The sample demonstrates inserting and retrieving records efficiently.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include <boost/container/flat_map.hpp>
|
|
#include <boost/container/stable_vector.hpp>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
// Define a Simple Database Table Structure
|
|
struct Record {
|
|
int id; // Primary Key
|
|
std::string name; // Represents record data
|
|
|
|
Record(int id, std::string name) : id(id), name(std::move(name)) {}
|
|
};
|
|
|
|
// Implement a Database Table Class
|
|
class DatabaseTable {
|
|
public:
|
|
using RecordStorage = boost::container::stable_vector<Record>;
|
|
using IndexMap = boost::container::flat_map<int, size_t>; // Fast lookup
|
|
|
|
void insert(int id, const std::string& name) {
|
|
size_t index = records.size();
|
|
records.emplace_back(id, name);
|
|
index_map[id] = index;
|
|
}
|
|
|
|
const Record* find(int id) {
|
|
auto it = index_map.find(id);
|
|
if (it != index_map.end()) {
|
|
return &records[it->second];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void print_all() const {
|
|
for (const auto& record : records) {
|
|
std::cout << "ID: " << record.id << ", Name: " << record.name << "\n";
|
|
}
|
|
}
|
|
|
|
private:
|
|
RecordStorage records; // Stores records in a stable manner
|
|
IndexMap index_map; // Provides fast ID lookups
|
|
};
|
|
|
|
// Demonstrate Database Operations
|
|
int main() {
|
|
DatabaseTable db;
|
|
|
|
// Insert records
|
|
db.insert(101, "Alice");
|
|
db.insert(102, "Bob");
|
|
db.insert(103, "Charlie");
|
|
|
|
// Retrieve a record
|
|
const Record* record = db.find(102);
|
|
if (record) {
|
|
std::cout << "Found: ID = " << record->id << ", Name = " << record->name << "\n";
|
|
} else {
|
|
std::cout << "Record not found!\n";
|
|
}
|
|
|
|
// Print all records
|
|
std::cout << "All records:\n";
|
|
db.print_all();
|
|
|
|
return 0;
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">Note</dt>
|
|
<dd>
|
|
<p>Key features of this sample are that it is memory-efficient (reducing fragmentation and with good performance), <code>stable_vector</code> prevents invalid references when resizing, and <code>flat_map</code> is faster than <code>std::map</code> for heavy use.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Run the program, the output should be:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">Found: ID = 102, Name = Bob
|
|
All records:
|
|
ID: 101, Name: Alice
|
|
ID: 102, Name: Bob
|
|
ID: 103, Name: Charlie</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_optimize_memory_allocation"><a class="anchor" href="#_optimize_memory_allocation"></a>Optimize Memory Allocation</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>As we are dealing with frequent allocations of small objects (the database records) we’ll enhance our database engine by using <a href="https://www.boost.org/libs/pool">Boost.Pool</a>. This library avoids repeated calls to <code>malloc</code>, <code>new</code> and <code>delete</code>.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include <boost/container/flat_map.hpp>
|
|
#include <boost/pool/pool.hpp>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
struct Record {
|
|
int id;
|
|
std::string name;
|
|
|
|
Record(int id, std::string name) : id(id), name(std::move(name)) {}
|
|
};
|
|
|
|
class DatabaseTable {
|
|
public:
|
|
using IndexMap = boost::container::flat_map<int, Record*>;
|
|
|
|
DatabaseTable() : recordPool(sizeof(Record)) {}
|
|
|
|
Record* insert(int id, const std::string& name) {
|
|
void* memory = recordPool.malloc(); // Allocate memory from the pool
|
|
if (!memory) {
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
Record* newRecord = new (memory) Record(id, name); // Placement new
|
|
index_map[id] = newRecord;
|
|
return newRecord;
|
|
}
|
|
|
|
void remove(int id) {
|
|
auto it = index_map.find(id);
|
|
if (it != index_map.end()) {
|
|
it->second->~Record(); // Call destructor
|
|
recordPool.free(it->second); // Free memory back to the pool
|
|
index_map.erase(it);
|
|
}
|
|
}
|
|
|
|
Record* find(int id) {
|
|
auto it = index_map.find(id);
|
|
return (it != index_map.end()) ? it->second : nullptr;
|
|
}
|
|
|
|
void print_all() {
|
|
for (const auto& pair : index_map) {
|
|
std::cout << "ID: " << pair.first << ", Name: " << pair.second->name << "\n";
|
|
}
|
|
}
|
|
|
|
~DatabaseTable() {
|
|
for (const auto& pair : index_map) {
|
|
pair.second->~Record();
|
|
recordPool.free(pair.second);
|
|
}
|
|
}
|
|
|
|
private:
|
|
boost::pool<> recordPool;
|
|
IndexMap index_map;
|
|
};
|
|
|
|
// Demonstrate Efficient Memory Use
|
|
int main() {
|
|
DatabaseTable db;
|
|
|
|
// Insert records
|
|
db.insert(101, "Alice");
|
|
db.insert(102, "Bob");
|
|
db.insert(103, "Charlie");
|
|
|
|
// Retrieve a record
|
|
Record* record = db.find(102);
|
|
if (record) {
|
|
std::cout << "Found: ID = " << record->id << ", Name = " << record->name << "\n";
|
|
}
|
|
|
|
// Remove a record
|
|
db.remove(102);
|
|
if (!db.find(102)) {
|
|
std::cout << "Record 102 removed successfully.\n";
|
|
}
|
|
|
|
// Print all records
|
|
std::cout << "All records:\n";
|
|
db.print_all();
|
|
|
|
return 0;
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="dlist">
|
|
<dl>
|
|
<dt class="hdlist1">Note</dt>
|
|
<dd>
|
|
<p>Custom <em>Object Pools</em> can be tuned for your specific object sizes.</p>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The output should be:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">Found: ID = 102, Name = Bob
|
|
Record 102 removed successfully.
|
|
All records:
|
|
ID: 101, Name: Alice
|
|
ID: 103, Name: Charlie</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_use_persistent_shared_memory"><a class="anchor" href="#_use_persistent_shared_memory"></a>Use Persistent Shared Memory</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>In a realistic database environment, you would probably want to enable a shared-memory database table that multiple processes can access simultaneously. For this, we need the features of <a href="https://www.boost.org/libs/interprocess">Boost.Interprocess</a>. This library enables multiple processes to share the same data faster than inter-process communication (IPC) via files or sockets, and includes mutexes and condition variables.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include <boost/interprocess/managed_shared_memory.hpp>
|
|
#include <boost/interprocess/containers/vector.hpp>
|
|
#include <iostream>
|
|
|
|
namespace bip = boost::interprocess;
|
|
|
|
const char* SHM_NAME = "SharedDatabase";
|
|
const char* TABLE_NAME = "UserTable";
|
|
const std::size_t MAX_USERS = 10;
|
|
|
|
struct UserRecord {
|
|
int id;
|
|
char name[32];
|
|
};
|
|
|
|
using ShmemAllocator = bip::allocator<UserRecord, bip::managed_shared_memory::segment_manager>;
|
|
using UserTable = bip::vector<UserRecord, ShmemAllocator>;
|
|
|
|
void create_table() {
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
|
|
bip::managed_shared_memory segment(bip::create_only, SHM_NAME, 65536);
|
|
const ShmemAllocator alloc_inst(segment.get_segment_manager());
|
|
UserTable* table = segment.construct<UserTable>(TABLE_NAME)(alloc_inst);
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
UserRecord user;
|
|
user.id = 1 + table->size();
|
|
std::snprintf(user.name, sizeof(user.name), "User%d", user.id);
|
|
table->push_back(user);
|
|
}
|
|
|
|
std::cout << "Shared memory table created with 3 initial users.\n";
|
|
}
|
|
|
|
void show_table() {
|
|
|
|
try
|
|
{
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
UserTable* table = segment.find<UserTable>(TABLE_NAME).first;
|
|
|
|
if (!table) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
std::cout << "User Table:\n";
|
|
for (const auto& user : *table) {
|
|
std::cout << " ID: " << user.id << ", Name: " << user.name << "\n";
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
std::cerr << "Shared Memory error - create a table\n";
|
|
}
|
|
}
|
|
|
|
void add_user() {
|
|
|
|
try
|
|
{
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
UserTable* table = segment.find<UserTable>(TABLE_NAME).first;
|
|
|
|
if (!table) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
if (table->size() >= MAX_USERS) {
|
|
std::cerr << "Table is full (max " << MAX_USERS << " users).\n";
|
|
return;
|
|
}
|
|
|
|
std::string name;
|
|
|
|
std::cout << "Enter user name: ";
|
|
std::getline(std::cin, name);
|
|
|
|
UserRecord user;
|
|
user.id = 1 + table->size();
|
|
std::snprintf(user.name, sizeof(user.name) - 1, "%s", name.c_str());
|
|
user.name[sizeof(user.name) - 1] = '\0';
|
|
|
|
table->push_back(user);
|
|
std::cout << "User added.\n";
|
|
}
|
|
catch (...)
|
|
{
|
|
std::cerr << "Shared Memory error - create a table\n";
|
|
}
|
|
}
|
|
|
|
void print_menu() {
|
|
std::cout << "\n=== Shared Memory User Table Menu ===\n";
|
|
std::cout << "1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: ";
|
|
}
|
|
|
|
int main() {
|
|
while (true) {
|
|
print_menu();
|
|
|
|
int choice = 0;
|
|
std::cin >> choice;
|
|
std::cin.ignore(); // discard newline
|
|
|
|
switch (choice) {
|
|
case 1:
|
|
create_table();
|
|
show_table();
|
|
break;
|
|
case 2:
|
|
show_table();
|
|
break;
|
|
case 3:
|
|
add_user();
|
|
break;
|
|
case 4:
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
break;
|
|
case 5:
|
|
std::cout << "Exiting...\n";
|
|
return 0;
|
|
default:
|
|
std::cout << "Invalid option. Try again.\n";
|
|
}
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Boost shared memory is persistent. Run the program, add some user records, and exit without choosing option <code>4</code>. Then run the program again and note the records you added have persisted.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>First run:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">=== Shared Memory User Table Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: 1
|
|
Shared memory table created with 3 initial users.
|
|
User Table:
|
|
ID: 1, Name: User1
|
|
ID: 2, Name: User2
|
|
ID: 3, Name: User3
|
|
|
|
=== Shared Memory User Table Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: 3
|
|
Enter user name: Nigel
|
|
User added.
|
|
|
|
=== Shared Memory User Table Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: 2
|
|
User Table:
|
|
ID: 1, Name: User1
|
|
ID: 2, Name: User2
|
|
ID: 3, Name: User3
|
|
ID: 4, Name: Nigel
|
|
|
|
=== Shared Memory User Table Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: 5
|
|
Exiting...</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Second run:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">=== Shared Memory User Table Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit: 2
|
|
User Table:
|
|
ID: 1, Name: User1
|
|
ID: 2, Name: User2
|
|
ID: 3, Name: User3
|
|
ID: 4, Name: Nigel</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_safely_allow_access_from_multiple_processes"><a class="anchor" href="#_safely_allow_access_from_multiple_processes"></a>Safely Allow Access from Multiple Processes</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>To safely allow multiple processes to access and modify shared memory concurrently in your <a href="https://www.boost.org/libs/interprocess">Boost.Interprocess</a> program, you should use interprocess synchronization primitives — like <code>interprocess_mutex</code> to guard critical sections.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include <boost/interprocess/managed_shared_memory.hpp>
|
|
#include <boost/interprocess/containers/vector.hpp>
|
|
#include <iostream>
|
|
|
|
namespace bip = boost::interprocess;
|
|
|
|
const char* SHM_NAME = "SharedDatabase";
|
|
const std::size_t MAX_USERS = 10;
|
|
|
|
struct UserRecord {
|
|
int id;
|
|
char name[32];
|
|
};
|
|
|
|
using SegmentManager = bip::managed_shared_memory::segment_manager;
|
|
using ShmemAllocator = bip::allocator<UserRecord, SegmentManager>;
|
|
using UserTable = bip::vector<UserRecord, ShmemAllocator>;
|
|
|
|
// Wrap the shared data and the mutex
|
|
struct SharedData {
|
|
bip::interprocess_mutex mutex;
|
|
UserTable table;
|
|
|
|
SharedData(const ShmemAllocator& alloc) : table(alloc) {}
|
|
};
|
|
|
|
const char* TABLE_NAME = "SharedUserTable";
|
|
|
|
void create_table() {
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
|
|
bip::managed_shared_memory segment(bip::create_only, SHM_NAME, 65536);
|
|
ShmemAllocator alloc_inst(segment.get_segment_manager());
|
|
|
|
// Construct SharedData in shared memory
|
|
segment.construct<SharedData>(TABLE_NAME)(alloc_inst);
|
|
|
|
std::cout << "Shared memory table created.\n";
|
|
}
|
|
|
|
void show_table() {
|
|
try {
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
SharedData* data = segment.find<SharedData>(TABLE_NAME).first;
|
|
if (!data) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
bip::scoped_lock<bip::interprocess_mutex> lock(data->mutex);
|
|
std::cout << "User Table:\n";
|
|
for (const auto& user : data->table) {
|
|
std::cout << " ID: " << user.id << ", Name: " << user.name << "\n";
|
|
}
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Error accessing shared memory. Is it created?\n";
|
|
}
|
|
}
|
|
|
|
void add_user() {
|
|
try {
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
SharedData* data = segment.find<SharedData>(TABLE_NAME).first;
|
|
if (!data) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
bip::scoped_lock<bip::interprocess_mutex> lock(data->mutex);
|
|
|
|
if (data->table.size() >= MAX_USERS) {
|
|
std::cerr << "Table is full (max " << MAX_USERS << " users).\n";
|
|
return;
|
|
}
|
|
|
|
std::string name;
|
|
std::cout << "Enter user name: ";
|
|
std::cin.ignore();
|
|
std::getline(std::cin, name);
|
|
|
|
UserRecord user;
|
|
user.id = 1 + static_cast<int>(data->table.size());
|
|
std::snprintf(user.name, sizeof(user.name) - 1, "%s", name.c_str());
|
|
user.name[sizeof(user.name) - 1] = '\0';
|
|
|
|
data->table.push_back(user);
|
|
std::cout << "User added.\n";
|
|
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Error accessing shared memory. Is it created?\n";
|
|
}
|
|
}
|
|
|
|
void print_menu() {
|
|
std::cout << "\n=== Shared Memory User Table Menu ===\n";
|
|
std::cout << "1. Create table 2. Show table 3. Add user 4. Clear shared memory 5. Exit\n";
|
|
std::cout << "Choose an option: ";
|
|
}
|
|
|
|
int main() {
|
|
while (true) {
|
|
print_menu();
|
|
|
|
int choice = 0;
|
|
std::cin >> choice;
|
|
|
|
switch (choice) {
|
|
case 1:
|
|
create_table();
|
|
show_table();
|
|
break;
|
|
case 2:
|
|
show_table();
|
|
break;
|
|
case 3:
|
|
add_user();
|
|
break;
|
|
case 4:
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
std::cout << "Shared memory cleared.\n";
|
|
break;
|
|
case 5:
|
|
std::cout << "Exiting...\n";
|
|
return 0;
|
|
default:
|
|
std::cout << "Invalid option. Try again.\n";
|
|
}
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Now it is safe to run this program from two, or more, terminal sessions.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_add_serialization_to_archive_the_database"><a class="anchor" href="#_add_serialization_to_archive_the_database"></a>Add Serialization to Archive the Database</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Finally, let’s add the features of <a href="https://www.boost.org/libs/serialization">Boost.Serialization</a> to allow us to save and restore snapshots of our shared-memory database, making it persistent across program runs even when the shared memory is cleared. We will extend our sample to serialize the records into an archive format.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-cpp hljs" data-lang="cpp">#include <boost/interprocess/managed_shared_memory.hpp> // For managing shared memory segments
|
|
#include <boost/interprocess/containers/vector.hpp> // STL-like vector that works inside shared memory
|
|
#include <boost/interprocess/sync/named_mutex.hpp> // Mutex across processes
|
|
#include <boost/serialization/vector.hpp> // Serialization support for std::vector
|
|
#include <boost/archive/text_oarchive.hpp> // For saving serialized data to text files
|
|
#include <boost/archive/text_iarchive.hpp> // For loading serialized data from text files
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
namespace bip = boost::interprocess;
|
|
|
|
// ---- Global configuration constants ----
|
|
const char* SHM_NAME = "SharedDatabase"; // Name of the shared memory segment
|
|
const char* TABLE_NAME = "UserTable"; // Name of the container object inside shared memory
|
|
const char* MUTEX_NAME = "SharedTableMutex"; // Name of the interprocess mutex
|
|
const std::size_t MAX_USERS = 10; // Maximum number of users allowed in table
|
|
|
|
// ---- User Record structure, supports Boost.Serialization ----
|
|
struct UserRecord {
|
|
int id; // Unique user ID
|
|
char name[32]; // Fixed-size character buffer for username
|
|
|
|
// Serialization function used by Boost.Archive
|
|
template<class Archive>
|
|
void serialize(Archive& ar, const unsigned int) {
|
|
ar& id;
|
|
|
|
// Wrap raw array in make_array so Boost knows how to handle it
|
|
ar& boost::serialization::make_array(name, sizeof(name));
|
|
}
|
|
};
|
|
|
|
// ---- Type aliases for clarity ----
|
|
using ShmemAllocator = bip::allocator<UserRecord, bip::managed_shared_memory::segment_manager>;
|
|
|
|
// Vector of UserRecords in shared memory
|
|
using UserTable = bip::vector<UserRecord, ShmemAllocator>;
|
|
|
|
// ---- Create a new table in shared memory ----
|
|
void create_table() {
|
|
|
|
// Remove any old shared memory segment and mutex (cleanup)
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
bip::named_mutex::remove(MUTEX_NAME);
|
|
|
|
// Create new shared memory segment of fixed size (64 KB here)
|
|
bip::managed_shared_memory segment(bip::create_only, SHM_NAME, 65536);
|
|
ShmemAllocator alloc(segment.get_segment_manager());
|
|
|
|
// Construct a UserTable object inside shared memory
|
|
UserTable* table = segment.construct<UserTable>(TABLE_NAME)(alloc);
|
|
|
|
// Pre-populate with three sample users
|
|
for (int i = 0; i < 3; ++i) {
|
|
UserRecord user;
|
|
user.id = 1 + table->size();
|
|
std::snprintf(user.name, sizeof(user.name), "User%d", user.id);
|
|
table->push_back(user);
|
|
}
|
|
|
|
std::cout << "Shared memory table created with 3 initial users.\n";
|
|
}
|
|
|
|
// ---- Display the contents of the table ----
|
|
void show_table() {
|
|
try {
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
bip::named_mutex mutex(bip::open_or_create, MUTEX_NAME);
|
|
|
|
// Lock table to prevent concurrent modifications
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
// Find UserTable in shared memory
|
|
UserTable* table = segment.find<UserTable>(TABLE_NAME).first;
|
|
if (!table) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
// Print all users
|
|
std::cout << "User Table:\n";
|
|
for (const auto& user : *table) {
|
|
std::cout << " ID: " << user.id << ", Name: " << user.name << "\n";
|
|
}
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Unable to access shared memory.\n";
|
|
}
|
|
}
|
|
|
|
// ---- Add a user to the shared memory table ----
|
|
void add_user() {
|
|
try {
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
bip::named_mutex mutex(bip::open_or_create, MUTEX_NAME);
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
UserTable* table = segment.find<UserTable>(TABLE_NAME).first;
|
|
if (!table || table->size() >= MAX_USERS) {
|
|
std::cerr << "Table not found or full.\n";
|
|
return;
|
|
}
|
|
|
|
// Get new user name from console
|
|
std::string name;
|
|
|
|
// Discard leftover newline from previous input
|
|
std::cin.ignore();
|
|
|
|
std::cout << "Enter user name: ";
|
|
std::getline(std::cin, name);
|
|
|
|
// Create new record and append
|
|
UserRecord user;
|
|
user.id = 1 + table->size();
|
|
std::snprintf(user.name, sizeof(user.name) - 1, "%s", name.c_str());
|
|
table->push_back(user);
|
|
|
|
std::cout << "User added.\n";
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Failed to add user.\n";
|
|
}
|
|
}
|
|
|
|
// ---- Save snapshot of current table to a text file ----
|
|
void save_snapshot(const std::string& filename) {
|
|
try {
|
|
bip::managed_shared_memory segment(bip::open_only, SHM_NAME);
|
|
bip::named_mutex mutex(bip::open_or_create, MUTEX_NAME);
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
UserTable* table = segment.find<UserTable>(TABLE_NAME).first;
|
|
if (!table) {
|
|
std::cerr << "Table not found.\n";
|
|
return;
|
|
}
|
|
|
|
// Copy data from shared memory into std::vector (heap memory)
|
|
std::vector<UserRecord> snapshot(table->begin(), table->end());
|
|
|
|
// Save serialized snapshot to file
|
|
std::ofstream ofs(filename);
|
|
boost::archive::text_oarchive oa(ofs);
|
|
oa << snapshot;
|
|
|
|
std::cout << "Snapshot saved to " << filename << "\n";
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Failed to save snapshot.\n";
|
|
}
|
|
}
|
|
|
|
// ---- Load snapshot from text file into shared memory ----
|
|
void load_snapshot(const std::string& filename) {
|
|
try {
|
|
|
|
// Open file and load into vector
|
|
std::ifstream ifs(filename);
|
|
if (!ifs) {
|
|
std::cerr << "Snapshot file not found.\n";
|
|
return;
|
|
}
|
|
|
|
std::vector<UserRecord> snapshot;
|
|
boost::archive::text_iarchive ia(ifs);
|
|
ia >> snapshot;
|
|
|
|
// Reset shared memory segment and mutex
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
bip::managed_shared_memory segment(bip::create_only, SHM_NAME, 65536);
|
|
bip::named_mutex::remove(MUTEX_NAME);
|
|
bip::named_mutex mutex(bip::create_only, MUTEX_NAME);
|
|
bip::scoped_lock<bip::named_mutex> lock(mutex);
|
|
|
|
// Recreate UserTable and repopulate
|
|
ShmemAllocator alloc(segment.get_segment_manager());
|
|
UserTable* table = segment.construct<UserTable>(TABLE_NAME)(alloc);
|
|
|
|
for (const auto& user : snapshot) {
|
|
table->push_back(user);
|
|
}
|
|
|
|
std::cout << "Snapshot loaded from " << filename << "\n";
|
|
}
|
|
catch (...) {
|
|
std::cerr << "Failed to load snapshot.\n";
|
|
}
|
|
}
|
|
|
|
// ---- Clear all shared memory resources ----
|
|
void clear_shared_memory() {
|
|
bip::shared_memory_object::remove(SHM_NAME);
|
|
bip::named_mutex::remove(MUTEX_NAME);
|
|
std::cout << "Shared memory cleared.\n";
|
|
}
|
|
|
|
// ---- Print the interactive menu ----
|
|
void print_menu() {
|
|
std::cout << "\n=== Shared Memory Menu ===\n"
|
|
<< "1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:";
|
|
}
|
|
|
|
// ---- Program entry point ----
|
|
int main() {
|
|
while (true) {
|
|
print_menu();
|
|
int choice;
|
|
std::cin >> choice;
|
|
|
|
switch (choice) {
|
|
case 1:
|
|
create_table();
|
|
|
|
// Show immediately after creation
|
|
show_table();
|
|
break;
|
|
case 2: show_table(); break;
|
|
case 3: add_user(); break;
|
|
case 4: save_snapshot("snapshot.txt"); break;
|
|
case 5:
|
|
load_snapshot("snapshot.txt");
|
|
show_table();
|
|
break;
|
|
case 6: clear_shared_memory(); break;
|
|
case 7: return 0;
|
|
default: std::cout << "Invalid choice.\n";
|
|
}
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Run the sample, and verify that the saved file persists after shared memory has been cleared.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-text hljs" data-lang="text">=== Shared Memory Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:1
|
|
Shared memory table created with 3 initial users.
|
|
User Table:
|
|
ID: 1, Name: User1
|
|
ID: 2, Name: User2
|
|
ID: 3, Name: User3
|
|
|
|
=== Shared Memory Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:3
|
|
Enter user name: Nigel
|
|
User added.
|
|
|
|
=== Shared Memory Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:4
|
|
Snapshot saved to snapshot.txt
|
|
|
|
=== Shared Memory Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:6
|
|
Shared memory cleared.
|
|
|
|
=== Shared Memory Menu ===
|
|
1. Create table 2. Show table 3. Add user 4. Save snapshot 5. Load snapshot 6. Clear shared memory 7. Exit:5
|
|
Snapshot loaded from snapshot.txt
|
|
User Table:
|
|
ID: 1, Name: User1
|
|
ID: 2, Name: User2
|
|
ID: 3, Name: User3
|
|
ID: 4, Name: Nigel</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_next_steps"><a class="anchor" href="#_next_steps"></a>Next Steps</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>In the design of a database, consider all the independent processes, and how they might access persistent memory, for example:</p>
|
|
</div>
|
|
<div class="imageblock">
|
|
<div class="content">
|
|
<img src="_images/database-persistent-memory.png" alt="database persistent memory">
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Perhaps now consider <a href="https://www.boost.org/libs/filesystem">Boost.Filesystem</a> for file management, and for a heavier duty database engine - integrate <a href="https://www.boost.org/libs/asio">Boost.Asio</a> to handle remote database transactions. Referring to the <a href="task-networking.html" class="xref page">Networking</a> sample would be a good place to start.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The Boost libraries have a lot to offer this particular scenario!</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="_see_also"><a class="anchor" href="#_see_also"></a>See Also</h2>
|
|
<div class="sectionbody">
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="https://www.boost.org/doc/libs/latest/libs/libraries.htm#Containers">Category: Containers</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/doc/libs/latest/libs/libraries.htm#Data">Category: Data structures</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="https://www.boost.org/doc/libs/latest/libs/libraries.htm#Memory">Category: Memory</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="edit-this-page">
|
|
<a href="file:///Users/julio/dev/website-v2-docs/user-guide/modules/ROOT/pages/task-database.adoc">Edit this Page</a>
|
|
</div>
|
|
<nav class="pagination">
|
|
<span class="prev"><a href="advanced-introduction.html">Introduction</a></span>
|
|
<span class="next"><a href="task-machine-learning.html">Machine Learning</a></span>
|
|
</nav>
|
|
</article>
|
|
</div>
|
|
<div id="footer">
|
|
<script id="site-script" src="../_/js/site.js" data-ui-root-path="../_"></script>
|
|
<script async src="../_/js/vendor/highlight.js"></script>
|
|
<script async src="../_/js/vendor/tabs.js" data-sync-storage-key="preferred-tab"></script>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|