-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Thread-safe Postgres connections
- Loading branch information
Showing
10 changed files
with
128 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ struct config { | |
|
||
struct pg_t { | ||
std::string opts; | ||
duration_t timeout = 1000ms; | ||
}; | ||
|
||
struct redis_t { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,43 @@ | ||
#include "pg.h" | ||
|
||
static std::shared_ptr<datastore::pg::conn_t> _conn = nullptr; | ||
#include "err/errors.h" | ||
|
||
static datastore::config::pg_t _conf; | ||
static datastore::pg::conn_t _conn = nullptr; | ||
|
||
namespace datastore { | ||
namespace pg { | ||
std::shared_ptr<conn_t> conn() { | ||
// FIXME: check if initialised | ||
return _conn; | ||
conn_t::element_type &connection::conn() const { | ||
return *_conn; | ||
} | ||
|
||
result_t exec(std::string_view qry) { | ||
nontxn_t tx(*conn()); | ||
return tx.exec(qry); | ||
conn_t::element_type &connection::reconnect() { | ||
_conn = connect(); | ||
return *_conn; | ||
} | ||
|
||
void init(const config::pg_t &c) { | ||
connection conn() { | ||
if (!_conn) { | ||
throw err::DatastorePgConnectionUnavailable(); | ||
} | ||
|
||
static std::timed_mutex mutex; | ||
if (!mutex.try_lock_for(_conf.timeout)) { | ||
throw err::DatastorePgTimeout(); | ||
} | ||
|
||
return connection(_conn, connection::lock_t(mutex, std::adopt_lock)); | ||
} | ||
|
||
conn_t connect() { | ||
// Ref: https://www.postgresql.org/docs/current/libpq-envars.html | ||
_conn = std::make_shared<conn_t>(c.opts); | ||
_conn = std::make_shared<conn_t::element_type>(_conf.opts); | ||
return _conn; | ||
} | ||
|
||
void init(const config::pg_t &c) { | ||
_conf = c; | ||
connect(); | ||
} | ||
} // namespace pg | ||
} // namespace datastore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include <thread> | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include "pg.h" | ||
#include "testing.h" | ||
|
||
TEST(pg, concurrency) { | ||
if (std::thread::hardware_concurrency() < 2) { | ||
GTEST_SKIP() << "Not enough hardware support to run concurrency tests"; | ||
} | ||
|
||
auto conf = datastore::testing::conf(); | ||
conf.pg.timeout = 50ms; | ||
ASSERT_NO_THROW(datastore::pg::init(conf.pg)); | ||
|
||
// Success: timeout while waiting for connection lock | ||
{ | ||
std::thread t1([conf]() { | ||
auto conn = datastore::pg::conn(); | ||
std::this_thread::sleep_for(conf.pg.timeout * 5); | ||
}); | ||
|
||
std::thread t2([]() { | ||
// Connection is locked into t1 scope, expect a timeout | ||
EXPECT_THROW(datastore::pg::conn(), err::DatastorePgTimeout); | ||
}); | ||
|
||
t1.join(); | ||
t2.join(); | ||
} | ||
} | ||
|
||
TEST(pg, conn) { | ||
// Error: connection unavailable | ||
{ EXPECT_THROW(datastore::pg::conn(), err::DatastorePgConnectionUnavailable); } | ||
} | ||
|
||
TEST(pg, reconnect) { | ||
auto conf = datastore::testing::conf(); | ||
ASSERT_NO_THROW(datastore::pg::init(conf.pg)); | ||
|
||
// Success: reconnect | ||
{ | ||
auto c = datastore::pg::connect(); | ||
c->close(); | ||
|
||
EXPECT_NO_THROW(datastore::pg::exec("select 'ping';")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters