diff -r fd5765c5068c -r f210681d9dd0 src/server/daemon/resourcepool.c --- 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;itype->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) {