Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
connection_pool_demo.cpp File Reference

Demonstrates multi-threaded database usage with independent database_manager instances. More...

#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include <mutex>
#include <variant>
#include "database/database_manager.h"
#include "database/core/database_context.h"
Include dependency graph for connection_pool_demo.cpp:

Go to the source code of this file.

Functions

static void thread_print (int thread_id, const std::string &msg)
 Thread-safe print helper.
 
static void worker (int thread_id, const std::string &connection_string)
 Worker function: creates its own connection, inserts data, reads it back, and disconnects.
 
int main ()
 

Variables

static std::mutex cout_mutex
 

Detailed Description

Demonstrates multi-threaded database usage with independent database_manager instances.

This example shows how to:

  • Create multiple database_manager instances for concurrent use
  • Use separate database_context instances per thread
  • Execute queries safely from multiple threads
  • Aggregate results from parallel database operations

Design note: database_manager instances are not thread-safe for concurrent operations on the same instance. Each thread should use its own database_manager. The underlying connection pooling is handled server-side (ProxyMode) or by creating separate connections.

Prerequisites:

  • A running PostgreSQL server
  • Update the connection string below with valid credentials

Definition in file connection_pool_demo.cpp.

Function Documentation

◆ main()

int main ( )

Definition at line 98 of file connection_pool_demo.cpp.

99{
100 std::cout << "=== connection_pool_demo example ===" << std::endl;
101
102 std::string connection_string
103 = "host=localhost port=5432 dbname=example_db user=user password=password";
104
105 // Setup: create the demo table using a single connection
106 {
107 auto context = std::make_shared<database_context>();
108 auto db = std::make_shared<database_manager>(context);
109 db->set_mode(database_types::postgres);
110
111 auto connect_result = db->connect_result(connection_string);
112 if (!connect_result.is_ok())
113 {
114 std::cerr << "Setup connection failed. Ensure PostgreSQL is running."
115 << std::endl;
116 return 1;
117 }
118
119 db->create_query_result(R"(
120 CREATE TABLE IF NOT EXISTS pool_demo (
121 id SERIAL PRIMARY KEY,
122 thread_id INTEGER NOT NULL,
123 message VARCHAR(200)
124 )
125 )");
126 db->execute_query_result("DELETE FROM pool_demo");
127 db->disconnect_result();
128 std::cout << "Setup complete" << std::endl;
129 }
130
131 // Launch multiple threads, each with its own connection
132 const int num_threads = 4;
133 std::vector<std::thread> threads;
134 threads.reserve(num_threads);
135
136 std::cout << "\nLaunching " << num_threads << " worker threads..." << std::endl;
137
138 for (int i = 0; i < num_threads; ++i)
139 {
140 threads.emplace_back(worker, i, connection_string);
141 }
142
143 // Wait for all threads to complete
144 for (auto& t : threads)
145 {
146 t.join();
147 }
148 std::cout << "\nAll threads completed" << std::endl;
149
150 // Final verification: read all inserted rows
151 {
152 auto context = std::make_shared<database_context>();
153 auto db = std::make_shared<database_manager>(context);
154 db->set_mode(database_types::postgres);
155
156 auto connect_result = db->connect_result(connection_string);
157 if (connect_result.is_ok())
158 {
159 auto result = db->select_query_result(
160 "SELECT thread_id, message FROM pool_demo ORDER BY thread_id");
161 if (result.is_ok())
162 {
163 std::cout << "\nFinal table contents (" << result.value().size()
164 << " rows):" << std::endl;
165 for (const auto& row : result.value())
166 {
167 for (const auto& [col, val] : row)
168 {
169 std::cout << " " << col << " = ";
170 std::visit([](const auto& v) { std::cout << v; }, val);
171 std::cout << " ";
172 }
173 std::cout << std::endl;
174 }
175 }
176 db->disconnect_result();
177 }
178 }
179
180 std::cout << "\n=== connection_pool_demo example completed ===" << std::endl;
181 return 0;
182}
static void worker(int thread_id, const std::string &connection_string)
Worker function: creates its own connection, inserts data, reads it back, and disconnects.

References worker().

Here is the call graph for this function:

◆ thread_print()

static void thread_print ( int thread_id,
const std::string & msg )
static

Thread-safe print helper.

Definition at line 44 of file connection_pool_demo.cpp.

45{
46 std::lock_guard<std::mutex> lock(cout_mutex);
47 std::cout << " [thread " << thread_id << "] " << msg << std::endl;
48}
static std::mutex cout_mutex

References cout_mutex.

Referenced by worker().

Here is the caller graph for this function:

◆ worker()

static void worker ( int thread_id,
const std::string & connection_string )
static

Worker function: creates its own connection, inserts data, reads it back, and disconnects.

Examples
/home/runner/work/database_system/database_system/database/async/async_operations.h.

Definition at line 54 of file connection_pool_demo.cpp.

55{
56 // Each thread creates its own context and manager
57 auto context = std::make_shared<database_context>();
58 auto db = std::make_shared<database_manager>(context);
59 db->set_mode(database_types::postgres);
60
61 auto connect_result = db->connect_result(connection_string);
62 if (!connect_result.is_ok())
63 {
64 thread_print(thread_id, "Connection failed");
65 return;
66 }
67 thread_print(thread_id, "Connected");
68
69 // Insert a row identifying this thread
70 std::string insert_sql
71 = "INSERT INTO pool_demo (thread_id, message) VALUES ("
72 + std::to_string(thread_id) + ", 'Hello from thread "
73 + std::to_string(thread_id) + "')";
74
75 auto insert_result = db->execute_query_result(insert_sql);
76 if (insert_result.is_ok())
77 {
78 thread_print(thread_id, "Row inserted");
79 }
80 else
81 {
82 thread_print(thread_id, "Insert failed");
83 }
84
85 // Read back all rows (each thread sees the current state)
86 auto select_result = db->select_query_result(
87 "SELECT thread_id, message FROM pool_demo ORDER BY thread_id");
88 if (select_result.is_ok())
89 {
90 thread_print(thread_id,
91 "Read " + std::to_string(select_result.value().size()) + " row(s)");
92 }
93
94 db->disconnect_result();
95 thread_print(thread_id, "Disconnected");
96}
static void thread_print(int thread_id, const std::string &msg)
Thread-safe print helper.

References thread_print().

Referenced by main(), database::async::async_executor::shutdown(), and database::integrated::adapters::backends::fallback_thread_backend::shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ cout_mutex

std::mutex cout_mutex
static

Definition at line 39 of file connection_pool_demo.cpp.

Referenced by thread_print().