Comments (2)
Ideally, rapi_startup()
happens only in dbConnect()
. This means that argument checks in duckdb()
are deferred, but that should be of little relevance in practice.
from duckdb-r.
We can have the cake and eat it too.
On the R side, the driver holds a pointer to the database that can be either a shared or a weak pointer on the C++ side. When calling duckdb()
, we call rapi_startup()
and store the results as a shared pointer. On dbConnect()
, the connection owns the database pointer, and the driver's pointer is demoted to a weak pointer. As long as the connection is alive, we can reuse the same database object. When the last connection to the database is closed, the database pointer is released and all drivers' weak pointers become invalid -- we create a new database.
cpp11::cpp_source(
code = '
#define CPP11_USE_FMT
#include "cpp11/function.hpp"
#include "cpp11/list.hpp"
#include "cpp11/external_pointer.hpp"
struct Db {
Db() { cpp11::message("Db(): {}", (void*)this); }
~Db() { cpp11::message("~Db(): {}", (void*)this); }
};
class Dual {
public:
Dual(Db* db) : precious_(db) { cpp11::message("Dual(db): {}", (void*)this); }
Dual(std::shared_ptr<Db> db) : precious_(db) { cpp11::message("Dual(dbp): {}", (void*)this); }
Dual(Dual* dual) : precious_(dual->get()) {
if (!precious_) {
cpp11::stop("dual is already released");
}
cpp11::message("Dual(dual): {}", (void*)this);
}
~Dual() { cpp11::message("~Dual(): {}", (void*)this); }
std::shared_ptr<Db> get() const {
if (precious_) {
return precious_;
} else {
return disposable_.lock();
}
}
std::shared_ptr<Db> operator->() const {
return get();
}
bool has() const {
return !!get();
}
void lock() {
if (precious_) {
cpp11::stop("already locked");
}
precious_ = disposable_.lock();
disposable_.reset();
}
void unlock() {
if (!precious_) {
cpp11::stop("already unlocked");
}
disposable_ = precious_;
precious_.reset();
}
void reset() {
precious_.reset();
disposable_.reset();
}
private:
std::shared_ptr<Db> precious_;
std::weak_ptr<Db> disposable_;
};
[[cpp11::register]]
SEXP new_dual() {
cpp11::external_pointer<Dual> x(new Dual(new Db()));
return x;
}
[[cpp11::register]]
SEXP clone_dual(SEXP dual__) {
cpp11::external_pointer<Dual> dual_(dual__);
auto dual = dual_.get();
if (!dual) {
cpp11::stop("dual is already released");
}
cpp11::external_pointer<Dual> x(new Dual(dual));
return x;
}
[[cpp11::register]]
bool has_db_from_dual(SEXP dual__) {
cpp11::external_pointer<Dual> dual_(dual__);
auto dual = dual_.get();
if (!dual) {
return false;
}
dual_.get()->has();
}
[[cpp11::register]]
void release_dual(SEXP dual__) {
cpp11::external_pointer<Dual> dual_(dual__);
dual_.reset();
}
'
)
x <- new_dual()
#> Db(): 0x6000024fccb0
#> Dual(db): 0x6000026f2da0
db <- x
db
#> <pointer: 0x6000026f2da0>
has_db_from_dual(db)
#> [1] FALSE
gc()
#> used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
#> Ncells 763838 40.8 1454181 77.7 NA 1454181 77.7
#> Vcells 1340195 10.3 8388608 64.0 24576 2048527 15.7
has_db_from_dual(db)
#> [1] FALSE
y <- clone_dual(x)
#> Dual(dual): 0x6000026f2e00
has_db_from_dual(db)
#> [1] FALSE
release_dual(x)
#> ~Dual(): 0x6000026f2da0
has_db_from_dual(db)
#> [1] FALSE
release_dual(y)
#> ~Dual(): 0x6000026f2e00
#> ~Db(): 0x6000024fccb0
has_db_from_dual(db)
#> [1] FALSE
clone_dual(db)
#> Error: dual is already released
Created on 2024-03-24 with reprex v2.1.0
from duckdb-r.
Related Issues (20)
- Segfault when creating persistent database HOT 4
- Feature request: Support for clock::add_days and clock::add_years HOT 3
- Interop with spatial extension HOT 2
- Request for duckdb_read_csv2 function and clarification on data types in duckdb_read_csv HOT 4
- Failing to connect in v0.10 with dbdir HOT 4
- Do not use RE2 on CRAN HOT 4
- Deprecate `dbConnect(dbdir, config, read_only)`
- Reenable RE2 checks on CRAN
- Cannot read CSV or Parquet with dplyr::tbl HOT 7
- Error Writing Encrypted Parquet Files on Windows HOT 2
- duckdb fails filtering OSM files due to `Unknown column type for prepare: MAP(VARCHAR, VARCHAR)` error HOT 9
- Error: rapi_prepare: Unknown column type for prepare: MAP(BLOB, BLOB) when using parquet_metadata with dbGetQuery HOT 2
- Execute queries without registering Data Frames / Arrow Tables HOT 5
- Undefined behavior with list columns HOT 12
- add `temporary` parameter to `duckdb_read_csv()` HOT 2
- `round()` semantics of R-version differs from its duckdb-translation HOT 1
- Use proper std::isnan in C++ code, not C99 versions which may not compile HOT 4
- Error: String contains null byte
- `NULL` mapped to `NA_integer_` HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from duckdb-r.