Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threadsafe connection #1395

Draft
wants to merge 9 commits into
base: dev
Choose a base branch
from
Draft

Conversation

trueqbit
Copy link
Collaborator

@trueqbit trueqbit commented Feb 4, 2025

With C++20 a more light-weight binary semaphore can be conditionally used to synchronize opening and closing a database connection.

Therefore, the connection holder should be minimally invasive and performant in all variants:

  1. single-threaded use
  2. opened once (open forever)
  3. concurrent open/close

Note: One important change is that things involved around setting up a database connection - like creating application-defined functions, setting pragma or limit values - must be done under the same synchronization point right after opening the database.
Caveat: Currently the connection cannot yet be recursively retained; think: user-provided 'on open' handlers.

The connection holder should be performant in all variants:
1. single-threaded use
2. opened once (open forever)
3. concurrent open/close

Hence, a light-weight binary semaphore is used to synchronize opening and closing a database connection.
A user-provided 'on open' handler and connection control options can now be specified in a declarative way when making the 'storage' object.
@trueqbit trueqbit force-pushed the experimental/threadsafe_connection branch from 564025d to 14a2aa0 Compare February 10, 2025 19:03
}

void release() {
// last one closes the connection.
// we assume that this might happen by any thread, therefore the counter must serve as a synchronization point.
if (this->_retain_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
if (_retainCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have code that omits this if the member variable starts with an underscore, so I removed it here as well.
What do you think? I find it easier to read and it's clear enough.


#ifdef SQLITE_ORM_CTAD_SUPPORTED
template<template<typename...> class R, class Tpl, size_t... Idx, class Projection = polyfill::identity>
constexpr auto create_from_tuple(Tpl&& tpl, std::index_sequence<Idx...>, Projection project = {}) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have it covered with unit tests

@@ -4,6 +4,26 @@

using namespace sqlite_orm;

#ifdef SQLITE_ORM_CTAD_SUPPORTED
TEST_CASE("connection control") {
const auto openForever = GENERATE(false, true);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is GENERATE?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Catch2 data generator.

const auto openForever = GENERATE(false, true);
SECTION("") {
SECTION("empty") {
auto storage = make_storage("", connection_control{openForever}, on_open([](sqlite3*) {}));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably we may add also on_open call counter increment inside on_open and checking that is was or wasn't called

#ifdef SQLITE_ORM_CTAD_SUPPORTED
TEST_CASE("connection control") {
const auto openForever = GENERATE(false, true);
SECTION("") {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of empty single session?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GENERATE repeats the SECTION following it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants