1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "resourcepool.h"
30 #include "request.h"
31 #include "session.h"
32 #include "../public/nsapi.h"
33 #include "../util/atomic.h"
34
35 #define RESOURCE_POOL_MAX_DEFAULT 32
36
37 #define RESOURCE_POOL_MAX_ALLOC 268435455
38
39 static CxMap *resource_pool_types;
40
41 int init_resource_pools(
void) {
42 resource_pool_types = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
4);
43 return resource_pool_types ?
0 :
1;
44 }
45
46 int resourcepool_register_type(
const char *type_name, ResourceType *type_info) {
47 if(cxMapPut(resource_pool_types, cx_hash_key_str(type_name), type_info)) {
48 log_ereport(
LOG_CATASTROPHE,
"resourcepool_register_type: OOM");
49 return 1;
50 }
51 return 0;
52 }
53
54
55
56 int resourcepool_new(ServerConfiguration *cfg, cxstring type, cxstring name, ConfigNode *node) {
57 ResourceType *restype = cxMapGet(resource_pool_types, cx_hash_key_bytes((
unsigned const char*)type.ptr, type.length));
58 if(!restype) {
59 log_ereport(
LOG_MISCONFIG,
"unknown resource pool type: %s", type.ptr);
60 return 1;
61 }
62
63 char *respool_name = cx_strdup_a(cfg->a, name).ptr;
64 if(!respool_name) {
65 log_ereport(
LOG_FAILURE,
"resourcepool_new: OOM");
66 return 1;
67 }
68
69
70
71
72 pblock *param = config_obj2pblock(cfg->pool, node);
73 if(!param) {
74 log_ereport(
LOG_FAILURE,
"resourcepool_new: OOM");
75 return 1;
76 }
77
78 ResourcePool *respool = pool_malloc(cfg->pool,
sizeof(ResourcePool));
79 if(!respool) {
80 log_ereport(
LOG_FAILURE,
"resourcepool_new: OOM");
81 return 1;
82 }
83 respool->pool = cfg->pool;
84
85 void *respool_data = restype->init(cfg->pool, name.ptr, param);
86 if(!respool_data) {
87 log_ereport(
LOG_FAILURE,
"Cannot create resource pool data: pool: %s type: %s", name.ptr, type.ptr);
88 return 1;
89 }
90
91 respool->name = respool_name;
92 respool->type = restype;
93 respool->data = respool_data;
94 respool->min =
4;
95 respool->max =
RESOURCE_POOL_MAX_DEFAULT;
96
97 respool->numcreated =
0;
98 respool->numresources =
0;
99
100
101
102
103 if(respool->max >
RESOURCE_POOL_MAX_ALLOC) {
104 respool->max =
RESOURCE_POOL_MAX_ALLOC;
105 log_ereport(
LOG_WARN,
"Resource pool %s: limit max to %d", name.ptr, respool->max);
106 }
107
108 respool->resalloc = respool->max;
109 respool->resources = pool_malloc(cfg->pool, respool->resalloc *
sizeof(ResourceDataPrivate*));
110
111 if(!respool->resources || cxMapPut(cfg->resources, cx_hash_key_bytes((
unsigned const char*)name.ptr, name.length), respool)) {
112 log_ereport(
LOG_FAILURE,
"Cannot add resource pool: OOM");
113
114 restype->destroy(respool_data);
115 return 1;
116 }
117
118 pthread_mutex_init(&respool->lock,
NULL);
119 pthread_cond_init(&respool->available,
NULL);
120
121 return 0;
122 }
123
124 static ResourceData* s_resourcepool_lookup(ServerConfiguration *cfg, Request *opt_rq, Session *opt_sn,
const char *name,
int flags) {
125 NSAPIRequest *request = (NSAPIRequest*)opt_rq;
126 NSAPISession *session = (NSAPISession*)opt_sn;
127 ResourceDataPrivate *resource =
NULL;
128
129
130 if(request && request->resources) {
131 resource = cxMapGet(request->resources, cx_hash_key_str(name));
132 if(resource) {
133 return &resource->data;
134 }
135 }
136
137 ResourcePool *respool = cxMapGet(cfg->resources, cx_hash_key_str(name));
138 if(!respool)
return NULL;
139
140
141 pthread_mutex_lock(&respool->lock);
142 WSBool createResource =
FALSE;
143 if(respool->numcreated < respool->min) {
144 createResource =
TRUE;
145 }
146
147 if(createResource) {
148
149 log_ereport(
LOG_DEBUG,
"resourcepool %s: create resource", name);
150
151 void *resourceData = respool->type->createresource(respool->data);
152 if(resourceData) {
153 respool->numcreated++;
154
155 resource = pool_malloc(respool->pool,
sizeof(ResourceDataPrivate));
156 if(resource) {
157 resource->data.data = respool->type->getresourcedata(resourceData);
158 resource->data.resourcepool = respool;
159 resource->resdata = resourceData;
160 }
else {
161 respool->type->freeresource(respool->data, resourceData);
162 log_ereport(
LOG_CATASTROPHE,
"resourcepool_lookup: OOM");
163 }
164 }
165
166 }
else if(respool->numresources >
0) {
167 resource = respool->resources[--respool->numresources];
168 }
else {
169
170 pthread_cond_wait(&respool->available, &respool->lock);
171 if(respool->numresources >
0) {
172 resource = respool->resources[--respool->numresources];
173 }
174 }
175
176
177
178 int err =
0;
179 if(resource) {
180 if(request && session) {
181 if(!request->resources) {
182 request->resources = cxHashMapCreate(pool_allocator(session->sn.pool),
CX_STORE_POINTERS,
8);
183 }
184
185 if(request->resources) {
186 if(cxMapPut(request->resources, cx_hash_key_str(name), resource)) {
187 err =
1;
188 }
189 }
else {
190 err =
1;
191 }
192 }
193
194 if(respool->type->prepare(respool->data, resource->resdata)) {
195 err = -
1;
196 }
197 }
198
199 if(err) {
200
201 log_ereport(
LOG_FAILURE,
"resourcepool_lookup: OOM");
202
203 resourcepool_destroy_resource(resource);
204 resource =
NULL;
205 }
206
207 pthread_mutex_unlock(&respool->lock);
208
209 return (ResourceData*)resource;
210 }
211
212 ResourceData* resourcepool_cfg_lookup(ServerConfiguration *cfg,
const char *name,
int flags) {
213 return s_resourcepool_lookup(cfg,
NULL,
NULL, name, flags);
214 }
215
216 ResourceData* resourcepool_lookup(Session *sn, Request *rq,
const char *name,
int flags) {
217 NSAPISession *session = (NSAPISession*)sn;
218 ServerConfiguration *cfg = session->config;
219 return s_resourcepool_lookup(cfg, rq, sn, name, flags);
220 }
221
222 void resourcepool_free(Session *sn, Request *rq, ResourceData *resource) {
223 NSAPIRequest *nsapi_rq = (NSAPIRequest *)rq;
224 ResourceDataPrivate *res = (ResourceDataPrivate*)resource;
225 ResourcePool *respool = resource->resourcepool;
226
227 if(nsapi_rq && !nsapi_rq->finished) {
228
229 if(!cxMapRemoveAndGet(nsapi_rq->resources, cx_hash_key_str(respool->name))) {
230 log_ereport(
LOG_FAILURE,
"resourcepool_free: cannot remove resource from request: potential double free");
231 }
232 }
233
234
235 if(respool->type->finish(respool->data, res->resdata)) {
236 log_ereport(
LOG_FAILURE,
"resourcepool_free: finish failed");
237 }
238
239 pthread_mutex_lock(&respool->lock);
240
241 if(respool->numresources >= respool->resalloc) {
242
243
244
245 respool->resalloc +=
8;
246 ResourceDataPrivate **new_res_array = pool_realloc(
247 respool->pool,
248 respool->resources,
249 respool->resalloc *
sizeof(ResourceDataPrivate*));
250 if(new_res_array) {
251 respool->resources = new_res_array;
252 }
else {
253 log_ereport(
LOG_FAILURE,
"resourcepool_free: OOM");
254 resourcepool_destroy_resource(res);
255 pthread_mutex_unlock(&respool->lock);
256 return;
257 }
258 }
259
260 respool->resources[respool->numresources++] = res;
261
262 pthread_cond_signal(&respool->available);
263 pthread_mutex_unlock(&respool->lock);
264 }
265
266 void resourcepool_destroy_resource(ResourceDataPrivate *res) {
267 res->data.resourcepool->numcreated--;
268 res->data.resourcepool->type->freeresource(res->data.resourcepool->data, res->resdata);
269 pool_free(res->data.resourcepool->pool, res);
270 }
271
272 void resourcepool_destroy(ResourcePool *respool) {
273
274 }
275