src/server/daemon/resourcepool.c

branch
webdav
changeset 272
f210681d9dd0
parent 271
fd5765c5068c
child 283
25e5b771677d
--- a/src/server/daemon/resourcepool.c	Tue Jan 25 17:45:56 2022 +0100
+++ b/src/server/daemon/resourcepool.c	Thu Jan 27 15:47:18 2022 +0100
@@ -30,6 +30,7 @@
 #include "request.h"
 #include "session.h"
 #include "../public/nsapi.h"
+#include "../util/atomic.h"
 
 #define RESOURCE_POOL_MAX_DEFAULT 32
 
@@ -83,7 +84,7 @@
     
     respool->type = restype;
     respool->data = respool_data;
-    respool->min = 0; // TODO: get from node
+    respool->min = 4; // TODO: get from node
     respool->max = RESOURCE_POOL_MAX_DEFAULT; // TODO: get from node
     
     // don't allow too large resource pools
@@ -94,7 +95,7 @@
     }
     
     respool->resalloc = respool->max;
-    respool->resources = pool_malloc(cfg->pool, respool->resalloc * sizeof(void*));
+    respool->resources = pool_malloc(cfg->pool, respool->resalloc * sizeof(ResourceDataPrivate*));
     
     if(!respool->resources || ucx_map_sstr_put(cfg->resources, name, respool)) {
         log_ereport(LOG_FAILURE, "Cannot add resource pool: OOM");
@@ -109,53 +110,123 @@
     return 0;
 }
 
-int resourcepool_create_resources(ResourcePool *pool, int num_res) {
-    if(num_res > pool->resalloc) {
-        num_res = pool->resalloc;
-    }
-    
-    for(int i=pool->numresources;i<num_res;i++) {
-        void *resource = pool->type->createresource(pool->data);
-        if(resource) {
-            pool->resources[pool->numresources++] = resource;
-        } else {
-            return 1; // error
-        }
-    }
-    
-    return 0;
-}
-
 ResourceData* resourcepool_lookup(Session *sn, Request *rq, const char *name, int flags) {
     NSAPIRequest *request = (NSAPIRequest*)rq;
     NSAPISession *session = (NSAPISession*)sn;
     ServerConfiguration *cfg = session->config;
     
-    ResourceDataPrivate *res = NULL;
+    ResourceDataPrivate *resource = NULL;
     
     // was this resource already used by this request?
     if(request->resources) {
-        res = ucx_map_cstr_get(request->resources, name);
-        if(res) {
-            return (ResourceData*)res;
+        resource = ucx_map_cstr_get(request->resources, name);
+        if(resource) {
+            return &resource->data;
         }
     }
     
-    // TODO: get cached resource
+    ResourcePool *respool = ucx_map_cstr_get(cfg->resources, name);
+    if(!respool) return NULL;
+
+    
+    pthread_mutex_lock(&respool->lock);
+    WSBool createResource = FALSE;
+    if(respool->numcreated < respool->min) {
+        createResource = TRUE;
+    }
     
-    /*
-    ResourceType *type = ucx_map_cstr_get(cfg->resources, name);
-    if(!type) {
-        return NULL;
+    if(createResource) {
+        // create a new resource and store it in the resourcepool
+        void *resourceData = respool->type->createresource(respool->data);
+        if(resourceData) {
+            respool->numcreated++;
+            
+            resource = pool_malloc(sn->pool, sizeof(ResourceDataPrivate));
+            if(resource) {
+                resource->data.data = respool->type->getresourcedata(resourceData);
+                resource->data.resourcepool = respool;
+            } else {
+                respool->type->freeresource(respool->data, resourceData);
+                log_ereport(LOG_CATASTROPHE, "resourcepool_lookup: OOM");
+            }
+        }
+        // else: respool->type->createresource does logging in case of errors
+    } else if(respool->numresources > 0) {
+        resource = respool->resources[--respool->numresources];
+    } else {
+        // wait for free resource
+        pthread_cond_wait(&respool->available, &respool->lock);
+        if(respool->numresources > 0) {
+            resource = respool->resources[--respool->numresources];
+        }        
     }
-    */
+    
+    // save the resource in the request object, for caching and also
+    // for cleanup later
+    int err = 0;
+    if(resource) {
+        if(!request->resources) {
+            request->resources = ucx_map_new_a(&session->allocator, 8);
+        }
+        
+        if(request->resources) {
+            if(ucx_map_cstr_put(request->resources, name, resource)) {
+                err = 1;
+            }
+        } else {
+            err = 1;
+        }
+    }
+    
+    if(err) {
+        // err == 1 caused by OOM
+        log_ereport(LOG_FAILURE, "resourcepool_lookup: OOM");
+        // cleanup
+        resourcepool_destroy_resource(resource);
+        resource = NULL;
+    }
+    
+    pthread_mutex_unlock(&respool->lock);
     
     
-    return NULL;
+    return &resource->data;
 }
 
-void resourcepool_free(ResourceData *data) {
+void resourcepool_free(Session *sn, Request *rq, ResourceData *resource) {
+    ResourceDataPrivate *res = (ResourceDataPrivate*)resource;
+    ResourcePool *respool = resource->resourcepool;
+    
+    pthread_mutex_lock(&respool->lock);
     
+    if(respool->numresources >= respool->resalloc) {
+        // actually respool->resalloc == respool->max
+        // and numresources should always be smaller
+        // however just be extra safe here
+        respool->resalloc += 8;
+        ResourceDataPrivate **new_res_array = pool_realloc(
+                respool->pool,
+                respool->resources,
+                respool->resalloc * sizeof(ResourceDataPrivate*));
+        if(new_res_array) {
+            respool->resources = new_res_array;
+        } else {
+            log_ereport(LOG_FAILURE, "resourcepool_free: OOM");
+            resourcepool_destroy_resource(res);
+            pthread_mutex_unlock(&respool->lock);
+            return;
+        }
+    }
+    
+    respool->resources[respool->numresources++] = res;
+    
+    pthread_cond_signal(&respool->available);
+    pthread_mutex_unlock(&respool->lock);
+}
+
+void resourcepool_destroy_resource(ResourceDataPrivate *res) {
+    res->data.resourcepool->numcreated--;
+    res->data.resourcepool->type->freeresource(res->data.resourcepool->data, res->resdata);
+    pool_free(res->data.resourcepool->pool, res);
 }
 
 void resourcepool_destroy(ResourcePool *respool) {

mercurial