Changeset: edf65208c59d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/edf65208c59d
Modified Files:
        gdk/gdk_heap.c
        sql/backends/monet5/UDF/pyapi3/conversion.h
        sql/backends/monet5/UDF/pyapi3/conversion3.c
        sql/backends/monet5/UDF/pyapi3/convert_loops.h
        sql/backends/monet5/UDF/pyapi3/pyapi3.c
Branch: default
Log Message:

Fix leakage in pyapi, both observed and potential.


diffs (231 lines):

diff --git a/gdk/gdk_heap.c b/gdk/gdk_heap.c
--- a/gdk/gdk_heap.c
+++ b/gdk/gdk_heap.c
@@ -45,6 +45,7 @@
 #include "monetdb_config.h"
 #include "gdk.h"
 #include "gdk_private.h"
+#include "gdk_interprocess.h"
 #include "mutils.h"
 
 static void *
@@ -606,7 +607,7 @@ void
 HEAPfree(Heap *h, bool rmheap)
 {
        if (h->base) {
-               if (h->farmid == 1) {
+               if (h->farmid == 1 && (h->storage == STORE_MEM || h->storage == 
STORE_MMAP || h->storage == STORE_PRIV)) {
                        QryCtx *qc = MT_thread_get_qry_ctx();
                        if (qc)
                                ATOMIC_SUB(&qc->datasize, h->size);
@@ -617,7 +618,11 @@ HEAPfree(Heap *h, bool rmheap)
                } else if (h->storage == STORE_CMEM) {
                        //heap is stored in regular C memory rather than GDK 
memory,so we call free()
                        free(h->base);
-               } else {        /* mapped file, or STORE_PRIV */
+               } else if (h->storage == STORE_MMAPABS) {
+                       size_t id;
+                       sscanf(h->filename, "%zu", &id);
+                       GDKreleasemmap(h->base, h->size, id);
+               } else if (h->storage != STORE_NOWN) {  /* mapped file, or 
STORE_PRIV */
                        gdk_return ret = GDKmunmap(h->base, h->size);
 
                        if (ret != GDK_SUCCEED) {
diff --git a/sql/backends/monet5/UDF/pyapi3/conversion.h 
b/sql/backends/monet5/UDF/pyapi3/conversion.h
--- a/sql/backends/monet5/UDF/pyapi3/conversion.h
+++ b/sql/backends/monet5/UDF/pyapi3/conversion.h
@@ -22,6 +22,7 @@ typedef struct {
        PyObject *numpy_mask; // PyArrayObject* with mask (NULL if there is no 
mask)
        void *array_data;        // void* pointer to data
        bool *mask_data;          // bool* pointer to mask data
+       size_t array_size;
        size_t count;             // amount of return elements
        size_t memory_size;   // memory size of each element
        lng mmap_id;
@@ -32,6 +33,7 @@ typedef struct {
 typedef struct {
        void *dataptr;                    // pointer to input data
        BAT *bat;                                 // pointer to input BAT
+       BAT *conv_bat;                    // converted input BAT
        int bat_type;                     // BAT type as TYPE_<type>
        sql_subtype *sql_subtype; // SQL typename (for _column_types)
        size_t count;                     // amount of elements in BAT
diff --git a/sql/backends/monet5/UDF/pyapi3/conversion3.c 
b/sql/backends/monet5/UDF/pyapi3/conversion3.c
--- a/sql/backends/monet5/UDF/pyapi3/conversion3.c
+++ b/sql/backends/monet5/UDF/pyapi3/conversion3.c
@@ -201,7 +201,7 @@ PyObject *PyArrayObject_FromBAT(PyInput 
                        goto wrapup;
                } else {
                        BAT *ret_bat = NULL;
-                       msg = ConvertFromSQLType(inp->bat, inp->sql_subtype, 
&ret_bat,
+                       msg = ConvertFromSQLType(b, inp->sql_subtype, &ret_bat,
                                                                         
&inp->bat_type);
                        if (msg != MAL_SUCCEED) {
                                freeException(msg);
@@ -500,7 +500,7 @@ PyObject *PyArrayObject_FromBAT(PyInput 
                goto wrapup;
        }
        if (b != inp->bat)
-               BBPunfix(b->batCacheid);
+               inp->conv_bat = b;              /* still in use, free later */
        return vararray;
 wrapup:
        *return_message = msg;
@@ -1131,6 +1131,7 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
        if (ConvertableSQLType(type)) {
                BAT *result;
                msg = ConvertToSQLType(NULL, b, type, &result, &bat_type);
+               BBPunfix(b->batCacheid);
                if (msg != MAL_SUCCEED) {
                        goto wrapup;
                }
@@ -1242,6 +1243,7 @@ str ConvertFromSQLType(BAT *b, sql_subty
                }
                if (res == MAL_SUCCEED) {
                        *ret_bat = BATdescriptor(result);
+                       BBPrelease(result);
                        *ret_type = TYPE_dbl;
                } else {
                        *ret_bat = NULL;
diff --git a/sql/backends/monet5/UDF/pyapi3/convert_loops.h 
b/sql/backends/monet5/UDF/pyapi3/convert_loops.h
--- a/sql/backends/monet5/UDF/pyapi3/convert_loops.h
+++ b/sql/backends/monet5/UDF/pyapi3/convert_loops.h
@@ -71,11 +71,14 @@
 #if defined(HAVE_FORK)
 #define CREATE_BAT_ZEROCOPY(bat, mtpe, batstore)                               
\
        {                                                                       
   \
-               bat = COLnew(seqbase, TYPE_##mtpe, 0, TRANSIENT);               
       \
+               bat = COLnew(seqbase, TYPE_void, 0, TRANSIENT);                 
       \
                if (bat == NULL) {                                              
       \
                        msg = createException(MAL, "pyapi3.eval", 
SQLSTATE(PY000) "Cannot create column"); \
                        goto wrapup;                                            
           \
                }                                                               
       \
+               bat->ttype = TYPE_##mtpe;                                       
       \
+               bat->twidth = ATOMsize(TYPE_##mtpe);                            
       \
+               bat->tshift = ATOMelmshift(b->twidth);                          
       \
                bat->tnil = false;                                              
       \
                bat->tnonil = true;                                             
       \
                bat->tkey = false;                                              
       \
@@ -97,31 +100,26 @@
                        nancheck_##mtpe(bat);                                   
           \
                }                                                               
       \
                                                                                
\
-               /*When we create a BAT a small part of memory is allocated, 
free it*/  \
-               GDKfree(bat->theap->base);                                      
       \
+               assert(bat->theap->base == NULL);                               
       \
                bat->theap->base =                                              
       \
                        &data[(index_offset * ret->count) * ret->memory_size];  
           \
-               bat->theap->size = ret->count * ret->memory_size;               
       \
-               bat->theap->free =                                              
       \
-                       bat->theap->size; /*There are no free places in the 
array*/        \
+               bat->theap->free = ret->count * ret->memory_size;               
       \
                bat->theap->dirty = true;                                       
       \
                /*If index_offset > 0, we are mapping part of a 
multidimensional */    \
                /* array.*/                                                     
       \
                /*The entire array will be cleared when the part with 
index_offset=0 */\
                /* is freed*/                                                   
       \
                /*So we set this part of the mapping to 'NOWN'*/                
       \
-               if (index_offset > 0)                                           
       \
+               if (index_offset > 0) {                                         
       \
+                       bat->theap->size = bat->theap->free;                    
           \
                        bat->theap->storage = STORE_NOWN;                       
           \
-               else {                                                          
       \
+               } else {                                                        
       \
+                       bat->theap->size = ret->array_size ? ret->array_size : 
bat->theap->free; \
                        bat->theap->storage = batstore;                         
           \
                        if (batstore == STORE_MMAPABS) {                        
           \
-                               /* If we are taking data from a MMAP file, set 
the filename to \
-                                * the absolute path */                         
               \
-                               char address[sizeof(bat->theap->filename)-4];   
               \
-                               GDKmmapfile(address, sizeof(address), 
ret->mmap_id);           \
-                               strconcat_len(bat->theap->filename,             
               \
-                                                         
sizeof(bat->theap->filename),                    \
-                                                         address, ".tmp", 
NULL);                          \
+                               /* Communicate the id to the GDK layer */       
               \
+                               snprintf(bat->theap->filename, 
sizeof(bat->theap->filename),   \
+                                                LLFMT, ret->mmap_id);          
                       \
                                ret->mmap_id = -1;                              
               \
                        }                                                       
           \
                }                                                               
       \
@@ -137,11 +135,14 @@
 #else
 #define CREATE_BAT_ZEROCOPY(bat, mtpe, batstore)                               
\
        {                                                                       
   \
-               bat = COLnew(seqbase, TYPE_##mtpe, 0, TRANSIENT);               
       \
+               bat = COLnew(seqbase, TYPE_void, 0, TRANSIENT);                 
       \
                if (bat == NULL) {                                              
       \
                        msg = createException(MAL, "pyapi3.eval", 
SQLSTATE(PY000) "Cannot create column");     \
                        goto wrapup;                                            
           \
                }                                                               
       \
+               bat->ttype = TYPE_##mtpe;                                       
       \
+               bat->twidth = ATOMsize(TYPE_##mtpe);                            
       \
+               bat->tshift = ATOMelmshift(b->twidth);                          
       \
                bat->tnil = false;                                              
       \
                bat->tnonil = true;                                             
       \
                bat->tkey = false;                                              
       \
@@ -162,22 +163,21 @@
                        bat->tnonil = false;                                    
           \
                        nancheck_##mtpe(bat);                                   
           \
                }                                                               
       \
-               /*When we create a BAT a small part of memory is allocated, 
free it*/  \
-               GDKfree(bat->theap->base);                                      
       \
+               assert(bat->theap->base == NULL);                               
       \
                bat->theap->base =                                              
       \
                        &data[(index_offset * ret->count) * ret->memory_size];  
           \
-               bat->theap->size = ret->count * ret->memory_size;               
       \
-               bat->theap->free =                                              
       \
-                       bat->theap->size; /*There are no free places in the 
array*/        \
+               bat->theap->free = ret->count * ret->memory_size;               
       \
                bat->theap->dirty = true;                                       
       \
                /*If index_offset > 0, we are mapping part of a 
multidimensional */    \
                /* array.*/                                                     
       \
                /*The entire array will be cleared when the part with 
index_offset=0 */\
                /* is freed*/                                                   
       \
                /*So we set this part of the mapping to 'NOWN'*/                
       \
-               if (index_offset > 0)                                           
       \
+               if (index_offset > 0) {                                         
       \
+                       bat->theap->size = bat->theap->free;                    
           \
                        bat->theap->storage = STORE_NOWN;                       
           \
-               else {                                                          
       \
+               } else {                                                        
       \
+                       bat->theap->size = ret->array_size ? ret->array_size : 
bat->theap->free; \
                        bat->theap->storage = batstore;                         
           \
                }                                                               
       \
                bat->theap->newstorage = STORE_MEM;                             
       \
diff --git a/sql/backends/monet5/UDF/pyapi3/pyapi3.c 
b/sql/backends/monet5/UDF/pyapi3/pyapi3.c
--- a/sql/backends/monet5/UDF/pyapi3/pyapi3.c
+++ b/sql/backends/monet5/UDF/pyapi3/pyapi3.c
@@ -183,7 +183,7 @@ static str PyAPIeval(Client cntxt, MalBl
        char *mmap_ptr;
        QueryStruct *query_ptr = NULL;
        int query_sem = -1;
-       int mmap_id = -1;
+       lng mmap_id = -1;
        size_t memory_size = 0;
        bool child_process = false;
        bool holds_gil = !mapped;
@@ -528,6 +528,7 @@ static str PyAPIeval(Client cntxt, MalBl
                                        goto wrapup;
                                }
                                ret->array_data = mmap_ptrs[i + 3];
+                               ret->array_size = mmap_sizes[i + 3];
                                ret->mask_data = NULL;
                                ret->numpy_array = NULL;
                                ret->numpy_mask = NULL;
@@ -1151,6 +1152,7 @@ static str PyAPIeval(Client cntxt, MalBl
                                ret->count = PyArray_DIMS((PyArrayObject 
*)ret->numpy_array)[0];
                                ret->array_data =
                                        PyArray_DATA((PyArrayObject 
*)ret->numpy_array);
+                               ret->array_size = ret->memory_size * ret->count;
                        }
 
                        descr->npy_type = ret->result_type;
@@ -1338,6 +1340,8 @@ wrapup:
                PyInput *inp = &pyinput_values[i - (pci->retc + 2 + 
has_card_arg)];
                if (inp->bat != NULL)
                        BBPunfix(inp->bat->batCacheid);
+               if (inp->conv_bat != NULL)
+                       BBPunfix(inp->conv_bat->batCacheid); /* delayed free */
        }
        if (pResult != NULL && gstate == 0) {
                // if there is a pResult here, we are running single threaded 
(LANGUAGE
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to