Changeset: 6ca60818140b for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=6ca60818140b
Modified Files:
        tools/embedded/Tests/lowlevel.R
        tools/embedded/embedded.c
        tools/embedded/embeddedr.c
        tools/embedded/rpackage/R/monetdb.R
Branch: embedded
Log Message:

Bug 3885


diffs (truncated from 316 to 300 lines):

diff --git a/tools/embedded/Tests/lowlevel.R b/tools/embedded/Tests/lowlevel.R
--- a/tools/embedded/Tests/lowlevel.R
+++ b/tools/embedded/Tests/lowlevel.R
@@ -20,8 +20,10 @@ test_that("one can connect", {
        con <- monetdb_embedded_connect()
        expect_that(con, is_a("monetdb_embedded_connection"))
        monetdb_embedded_disconnect(con)
+       # closed connections can be closed again
        monetdb_embedded_disconnect(con)
        expect_error(monetdb_embedded_disconnect(NULL))
+       expect_error(monetdb_embedded_disconnect(42))
 })
 
 test_that("db runs queries and returns results", {
@@ -37,6 +39,14 @@ test_that("db runs queries and returns r
        monetdb_embedded_disconnect(con)
 })
 
+test_that("a disconnected connection cannot be used", {
+       con <- monetdb_embedded_connect()
+       monetdb_embedded_query(con, "SELECT 42")
+       monetdb_embedded_disconnect(con)
+       res <- monetdb_embedded_query(con, "SELECT 42")
+       expect_equal(res$type, "!")
+})
+
 test_that("commit", {
        con <- monetdb_embedded_connect()
        monetdb_embedded_query(con, "START TRANSACTION")
@@ -116,6 +126,21 @@ test_that("inserting data", {
        monetdb_embedded_disconnect(con)
 })
 
+test_that("the garbage collector closes connections", {
+       # there are 64 connections max. if gc() does not close them, the last 
line will provoke a crash
+       conns <- lapply(1:64, function(x) monetdb_embedded_connect())
+       expect_error(monetdb_embedded_connect())
+
+       rm(conns)
+       gc()
+
+       conns <- lapply(1:64, function(x) monetdb_embedded_connect())
+       rm(conns)
+       gc()
+       monetdb_embedded_connect()
+})
+
+
 test_that("the logger does not misbehave", {
        con <- monetdb_embedded_connect()
        monetdb_embedded_query(con, "CREATE TABLE foo(i INTEGER, j INTEGER)")
@@ -124,11 +149,3 @@ test_that("the logger does not misbehave
        monetdb_embedded_disconnect(con)
 })
 
-test_that("the garbage collector closes connections", {
-       # there are 64 connections max. if gc() does not close them, the last 
line will provoke a crash
-       conns <- lapply(1:60, function(x) monetdb_embedded_connect())
-       rm(conns)
-       gc()
-       conns <- lapply(1:60, function(x) monetdb_embedded_connect())
-})
-
diff --git a/tools/embedded/embedded.c b/tools/embedded/embedded.c
--- a/tools/embedded/embedded.c
+++ b/tools/embedded/embedded.c
@@ -46,8 +46,9 @@ sqlcleanup_ptr_tpe sqlcleanup_ptr = NULL
 typedef void (*mvc_trans_ptr_tpe)(mvc*);
 mvc_trans_ptr_tpe mvc_trans_ptr = NULL;
 
-static MT_Lock monetdb_embedded_lock;
 int monetdb_embedded_initialized = 0;
+#define EMBEDDED_MAX_CONNS 64
+static void *monetdb_embedded_connections[EMBEDDED_MAX_CONNS];
 
 static void* lookup_function(char* func) {
        void *dl, *fun;
@@ -60,26 +61,62 @@ static void* lookup_function(char* func)
        return fun;
 }
 
+static int monetdb_valid_conn(void* conn) {
+       int i;
+       if (conn == NULL) {
+               return 0;
+       }
+       for (i = 0; i < EMBEDDED_MAX_CONNS; i++) {
+               if (conn == monetdb_embedded_connections[i]) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 void* monetdb_connect() {
+       void **conn = NULL;
+       int i;
+
+       if (!monetdb_embedded_initialized) {
+               return NULL;
+       }
+
+       for (i = 0; i < EMBEDDED_MAX_CONNS; i++) {
+               if (monetdb_embedded_connections[i] == NULL) {
+                       conn = &monetdb_embedded_connections[i];
+                       break;
+               }
+       }
+       if (conn == NULL) {
+               return NULL;
+       }
        Client c = MCforkClient(&mal_clients[0]);
        if ((*SQLinitClient_ptr)(c) != MAL_SUCCEED) {
                return NULL;
        }
        ((backend *) c->sqlcontext)->mvc->session->auto_commit = 1;
-       // TODO: keep track of pointers returned
+       *conn = c;
        return c;
 }
 
 void monetdb_disconnect(void* conn) {
-       if (conn == NULL) {
+       int i;
+       if (!monetdb_valid_conn(conn)) {
                return;
        }
-       MCcloseClient((Client) conn);
+       for (i = 0; i < EMBEDDED_MAX_CONNS; i++) {
+               if (conn == monetdb_embedded_connections[i]) {
+                       MCcloseClient((Client) conn);
+                       monetdb_embedded_connections[i] = NULL;
+                       return;
+               }
+       }
 }
 
 char* monetdb_startup(char* dbdir, char silent) {
        opt *set = NULL;
-       int setlen = 0;
+       int setlen = 0, i;
        str retval = MAL_SUCCEED;
        char* sqres = NULL;
        void* res = NULL;
@@ -98,8 +135,7 @@ char* monetdb_startup(char* dbdir, char 
                }
                goto cleanup;
        }
-       MT_lock_init(&monetdb_embedded_lock, "monetdb_embedded_lock");
-       MT_lock_set(&monetdb_embedded_lock);
+
        if (monetdb_embedded_initialized) goto cleanup;
 
        setlen = mo_builtin_settings(&set);
@@ -115,6 +151,9 @@ char* monetdb_startup(char* dbdir, char 
        GDKsetenv("mapi_disable", "true");
        GDKsetenv("sql_optimizer", "sequential_pipe");
 
+       for (i = 0; i < EMBEDDED_MAX_CONNS; i++) {
+               monetdb_embedded_connections[i] = NULL;
+       }
 
        if (silent) THRdata[0] = stream_blackhole_create();
        msab_dbpathinit(dbdir);
@@ -148,14 +187,16 @@ char* monetdb_startup(char* dbdir, char 
                goto cleanup;
        }
 
+       monetdb_embedded_initialized = true;
        c = monetdb_connect();
        if (c == NULL) {
+               monetdb_embedded_initialized = false;
                retval = GDKstrdup("Failed to initialize client");
                goto cleanup;
        }
-       monetdb_embedded_initialized = true;
+       GDKfataljumpenable = 0;
+
        // we do not want to jump after this point, since we cannot do so 
between threads
-       GDKfataljumpenable = 0;
        // sanity check, run a SQL query
        sqres = monetdb_query(c, "SELECT * FROM tables;", &res);
        if (sqres != NULL) {
@@ -167,18 +208,20 @@ char* monetdb_startup(char* dbdir, char 
        monetdb_disconnect(c);
 cleanup:
        mo_free_options(set, setlen);
-       MT_lock_unset(&monetdb_embedded_lock);
        return retval;
 }
 
 char* monetdb_query(void* conn, char* query, void** result) {
-       // TODO: check client pointer
        str res = MAL_SUCCEED;
        Client c = (Client) conn;
-       mvc* m = ((backend *) c->sqlcontext)->mvc;
+       mvc* m;
        if (!monetdb_embedded_initialized) {
                return GDKstrdup("Embedded MonetDB is not started");
        }
+       if (!monetdb_valid_conn(conn)) {
+               return GDKstrdup("Invalid connection");
+       }
+       m = ((backend *) c->sqlcontext)->mvc;
 
        while (*query == ' ' || *query == '\t') query++;
        if (strncasecmp(query, "START", 5) == 0) { // START TRANSACTION
@@ -216,7 +259,17 @@ char* monetdb_append(void* conn, const c
        Client c = (Client) conn;
        mvc* m = ((backend *) c->sqlcontext)->mvc;
 
-       assert(table != NULL && data != NULL && ncols > 0);
+       // TODO: check client pointer
+
+       if (!monetdb_embedded_initialized) {
+               return GDKstrdup("Embedded MonetDB is not started");
+       }
+       if(table == NULL || data == NULL || ncols < 1) {
+               return GDKstrdup("Invalid parameters");
+       }
+       if (!monetdb_valid_conn(conn)) {
+               return GDKstrdup("Invalid connection");
+       }
 
        // very black MAL magic below
        mb.var = GDKmalloc(nvar * sizeof(VarRecord*));
@@ -302,7 +355,6 @@ str monetdb_get_columns(void* conn, cons
 
 // TODO: fix this, it is not working correctly
 void monetdb_shutdown() {
-       MT_lock_set(&monetdb_embedded_lock);
        // kill SQL
        (*SQLepilogue_ptr)(NULL);
        // kill MAL & GDK
@@ -310,5 +362,4 @@ void monetdb_shutdown() {
        // clean up global state
        BBPresetfarms();
        monetdb_embedded_initialized = 0;
-       MT_lock_unset(&monetdb_embedded_lock);
 }
diff --git a/tools/embedded/embeddedr.c b/tools/embedded/embeddedr.c
--- a/tools/embedded/embeddedr.c
+++ b/tools/embedded/embeddedr.c
@@ -132,8 +132,11 @@ SEXP monetdb_append_R(SEXP connsexp, SEX
 
 
 SEXP monetdb_connect_R() {
-       SEXP conn = PROTECT(R_MakeExternalPtr(
-                       monetdb_connect(), R_NilValue, R_NilValue));
+       void* llconn = monetdb_connect();
+       if (!llconn) {
+               error("Could not create connection.");
+       }
+       SEXP conn = PROTECT(R_MakeExternalPtr(llconn, R_NilValue, R_NilValue));
        R_RegisterCFinalizer(conn, (void (*)(SEXP)) monetdb_disconnect_R);
        UNPROTECT(1);
        return conn;
diff --git a/tools/embedded/rpackage/R/monetdb.R 
b/tools/embedded/rpackage/R/monetdb.R
--- a/tools/embedded/rpackage/R/monetdb.R
+++ b/tools/embedded/rpackage/R/monetdb.R
@@ -36,7 +36,6 @@ monetdb_embedded_startup <- function(dir
        if (is.character(res)) {
                stop("Failed to initialize embedded MonetDB ", res)
        }
-
        monetdb_embedded_env$is_started <- TRUE
        monetdb_embedded_env$started_dir <- dir
        invisible(TRUE)
@@ -52,7 +51,7 @@ monetdb_embedded_query <- function(conn,
                stop("Need a single noreally flag as parameter.")
        }
        if (!inherits(conn, classname)) {
-               stop("Need a embedded monetdb connection as parameter")
+               stop("Invalid connection")
        }
        # make sure the query is terminated
        query <- paste(query, "\n;", sep="")
@@ -90,7 +89,7 @@ monetdb_embedded_append <- function(conn
                stop("Need a data frame as tdata parameter.")
        }
        if (!inherits(conn, classname)) {
-               stop("Need a embedded monetdb connection as parameter")
+               stop("Invalid connection")
        }
        .Call("monetdb_append_R", conn, schema, table, tdata, 
PACKAGE=libfilename)
 }
@@ -100,23 +99,23 @@ monetdb_embedded_connect <- function() {
        if (!monetdb_embedded_env$is_started) {
                stop("Call monetdb_embedded_startup() first")
        }
-       res <- .Call("monetdb_connect_R", PACKAGE=libfilename)
-       class(res) <- classname
-       return(res)
+       conn <- .Call("monetdb_connect_R", PACKAGE=libfilename)
+       class(conn) <- classname
+       return(conn)
 }
 
 monetdb_embedded_disconnect <- function(conn) {
        if (!inherits(conn, classname)) {
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to