src/server/daemon/resourcepool.c

branch
webdav
changeset 272
f210681d9dd0
parent 271
fd5765c5068c
child 283
25e5b771677d
equal deleted inserted replaced
271:fd5765c5068c 272:f210681d9dd0
28 28
29 #include "resourcepool.h" 29 #include "resourcepool.h"
30 #include "request.h" 30 #include "request.h"
31 #include "session.h" 31 #include "session.h"
32 #include "../public/nsapi.h" 32 #include "../public/nsapi.h"
33 #include "../util/atomic.h"
33 34
34 #define RESOURCE_POOL_MAX_DEFAULT 32 35 #define RESOURCE_POOL_MAX_DEFAULT 32
35 36
36 #define RESOURCE_POOL_MAX_ALLOC 268435455 37 #define RESOURCE_POOL_MAX_ALLOC 268435455
37 38
81 return 1; 82 return 1;
82 } 83 }
83 84
84 respool->type = restype; 85 respool->type = restype;
85 respool->data = respool_data; 86 respool->data = respool_data;
86 respool->min = 0; // TODO: get from node 87 respool->min = 4; // TODO: get from node
87 respool->max = RESOURCE_POOL_MAX_DEFAULT; // TODO: get from node 88 respool->max = RESOURCE_POOL_MAX_DEFAULT; // TODO: get from node
88 89
89 // don't allow too large resource pools 90 // don't allow too large resource pools
90 // this prevents the need to check malloc integer overflows 91 // this prevents the need to check malloc integer overflows
91 if(respool->max > RESOURCE_POOL_MAX_ALLOC) { 92 if(respool->max > RESOURCE_POOL_MAX_ALLOC) {
92 respool->max = RESOURCE_POOL_MAX_ALLOC; 93 respool->max = RESOURCE_POOL_MAX_ALLOC;
93 log_ereport(LOG_WARN, "Resource pool %s: limit max to %d", name.ptr, respool->max); 94 log_ereport(LOG_WARN, "Resource pool %s: limit max to %d", name.ptr, respool->max);
94 } 95 }
95 96
96 respool->resalloc = respool->max; 97 respool->resalloc = respool->max;
97 respool->resources = pool_malloc(cfg->pool, respool->resalloc * sizeof(void*)); 98 respool->resources = pool_malloc(cfg->pool, respool->resalloc * sizeof(ResourceDataPrivate*));
98 99
99 if(!respool->resources || ucx_map_sstr_put(cfg->resources, name, respool)) { 100 if(!respool->resources || ucx_map_sstr_put(cfg->resources, name, respool)) {
100 log_ereport(LOG_FAILURE, "Cannot add resource pool: OOM"); 101 log_ereport(LOG_FAILURE, "Cannot add resource pool: OOM");
101 // the only cleanup we have to do 102 // the only cleanup we have to do
102 restype->destroy(respool_data); 103 restype->destroy(respool_data);
107 pthread_cond_init(&respool->available, NULL); 108 pthread_cond_init(&respool->available, NULL);
108 109
109 return 0; 110 return 0;
110 } 111 }
111 112
112 int resourcepool_create_resources(ResourcePool *pool, int num_res) {
113 if(num_res > pool->resalloc) {
114 num_res = pool->resalloc;
115 }
116
117 for(int i=pool->numresources;i<num_res;i++) {
118 void *resource = pool->type->createresource(pool->data);
119 if(resource) {
120 pool->resources[pool->numresources++] = resource;
121 } else {
122 return 1; // error
123 }
124 }
125
126 return 0;
127 }
128
129 ResourceData* resourcepool_lookup(Session *sn, Request *rq, const char *name, int flags) { 113 ResourceData* resourcepool_lookup(Session *sn, Request *rq, const char *name, int flags) {
130 NSAPIRequest *request = (NSAPIRequest*)rq; 114 NSAPIRequest *request = (NSAPIRequest*)rq;
131 NSAPISession *session = (NSAPISession*)sn; 115 NSAPISession *session = (NSAPISession*)sn;
132 ServerConfiguration *cfg = session->config; 116 ServerConfiguration *cfg = session->config;
133 117
134 ResourceDataPrivate *res = NULL; 118 ResourceDataPrivate *resource = NULL;
135 119
136 // was this resource already used by this request? 120 // was this resource already used by this request?
137 if(request->resources) { 121 if(request->resources) {
138 res = ucx_map_cstr_get(request->resources, name); 122 resource = ucx_map_cstr_get(request->resources, name);
139 if(res) { 123 if(resource) {
140 return (ResourceData*)res; 124 return &resource->data;
141 } 125 }
142 } 126 }
143 127
144 // TODO: get cached resource 128 ResourcePool *respool = ucx_map_cstr_get(cfg->resources, name);
145 129 if(!respool) return NULL;
146 /* 130
147 ResourceType *type = ucx_map_cstr_get(cfg->resources, name); 131
148 if(!type) { 132 pthread_mutex_lock(&respool->lock);
149 return NULL; 133 WSBool createResource = FALSE;
150 } 134 if(respool->numcreated < respool->min) {
151 */ 135 createResource = TRUE;
152 136 }
153 137
154 return NULL; 138 if(createResource) {
155 } 139 // create a new resource and store it in the resourcepool
156 140 void *resourceData = respool->type->createresource(respool->data);
157 void resourcepool_free(ResourceData *data) { 141 if(resourceData) {
158 142 respool->numcreated++;
143
144 resource = pool_malloc(sn->pool, sizeof(ResourceDataPrivate));
145 if(resource) {
146 resource->data.data = respool->type->getresourcedata(resourceData);
147 resource->data.resourcepool = respool;
148 } else {
149 respool->type->freeresource(respool->data, resourceData);
150 log_ereport(LOG_CATASTROPHE, "resourcepool_lookup: OOM");
151 }
152 }
153 // else: respool->type->createresource does logging in case of errors
154 } else if(respool->numresources > 0) {
155 resource = respool->resources[--respool->numresources];
156 } else {
157 // wait for free resource
158 pthread_cond_wait(&respool->available, &respool->lock);
159 if(respool->numresources > 0) {
160 resource = respool->resources[--respool->numresources];
161 }
162 }
163
164 // save the resource in the request object, for caching and also
165 // for cleanup later
166 int err = 0;
167 if(resource) {
168 if(!request->resources) {
169 request->resources = ucx_map_new_a(&session->allocator, 8);
170 }
171
172 if(request->resources) {
173 if(ucx_map_cstr_put(request->resources, name, resource)) {
174 err = 1;
175 }
176 } else {
177 err = 1;
178 }
179 }
180
181 if(err) {
182 // err == 1 caused by OOM
183 log_ereport(LOG_FAILURE, "resourcepool_lookup: OOM");
184 // cleanup
185 resourcepool_destroy_resource(resource);
186 resource = NULL;
187 }
188
189 pthread_mutex_unlock(&respool->lock);
190
191
192 return &resource->data;
193 }
194
195 void resourcepool_free(Session *sn, Request *rq, ResourceData *resource) {
196 ResourceDataPrivate *res = (ResourceDataPrivate*)resource;
197 ResourcePool *respool = resource->resourcepool;
198
199 pthread_mutex_lock(&respool->lock);
200
201 if(respool->numresources >= respool->resalloc) {
202 // actually respool->resalloc == respool->max
203 // and numresources should always be smaller
204 // however just be extra safe here
205 respool->resalloc += 8;
206 ResourceDataPrivate **new_res_array = pool_realloc(
207 respool->pool,
208 respool->resources,
209 respool->resalloc * sizeof(ResourceDataPrivate*));
210 if(new_res_array) {
211 respool->resources = new_res_array;
212 } else {
213 log_ereport(LOG_FAILURE, "resourcepool_free: OOM");
214 resourcepool_destroy_resource(res);
215 pthread_mutex_unlock(&respool->lock);
216 return;
217 }
218 }
219
220 respool->resources[respool->numresources++] = res;
221
222 pthread_cond_signal(&respool->available);
223 pthread_mutex_unlock(&respool->lock);
224 }
225
226 void resourcepool_destroy_resource(ResourceDataPrivate *res) {
227 res->data.resourcepool->numcreated--;
228 res->data.resourcepool->type->freeresource(res->data.resourcepool->data, res->resdata);
229 pool_free(res->data.resourcepool->pool, res);
159 } 230 }
160 231
161 void resourcepool_destroy(ResourcePool *respool) { 232 void resourcepool_destroy(ResourcePool *respool) {
162 // TODO 233 // TODO
163 } 234 }

mercurial