File: | db/dbinit.c |
Warning: | line 1572, column 9 Using a fixed address is not portable because that address will probably not be valid in all environments or platforms |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * The contents of this file are subject to the Mozilla Public License | |||
3 | * Version 1.1 (the "License"); you may not use this file except in | |||
4 | * compliance with the License. You may obtain a copy of the License at | |||
5 | * http://mozilla.org/. | |||
6 | * | |||
7 | * Software distributed under the License is distributed on an "AS IS" | |||
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | |||
9 | * the License for the specific language governing rights and limitations | |||
10 | * under the License. | |||
11 | * | |||
12 | * The Original Code is AOLserver Code and related documentation | |||
13 | * distributed by AOL. | |||
14 | * | |||
15 | * The Initial Developer of the Original Code is America Online, | |||
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, | |||
17 | * Inc. All Rights Reserved. | |||
18 | * | |||
19 | * Alternatively, the contents of this file may be used under the terms | |||
20 | * of the GNU General Public License (the "GPL"), in which case the | |||
21 | * provisions of GPL are applicable instead of those above. If you wish | |||
22 | * to allow use of your version of this file only under the terms of the | |||
23 | * GPL and not to allow others to use your version of this file under the | |||
24 | * License, indicate your decision by deleting the provisions above and | |||
25 | * replace them with the notice and other provisions required by the GPL. | |||
26 | * If you do not delete the provisions above, a recipient may use your | |||
27 | * version of this file under either the License or the GPL. | |||
28 | */ | |||
29 | ||||
30 | ||||
31 | /* | |||
32 | * dbinit.c -- | |||
33 | * | |||
34 | * This file contains routines for creating and accessing | |||
35 | * pools of database handles. | |||
36 | */ | |||
37 | ||||
38 | #include "db.h" | |||
39 | ||||
40 | Ns_LogSeverity Ns_LogSqlDebug; | |||
41 | ||||
42 | /* | |||
43 | * The following structure defines a database pool. | |||
44 | */ | |||
45 | ||||
46 | struct Handle; | |||
47 | ||||
48 | typedef struct Pool { | |||
49 | const char *name; | |||
50 | const char *desc; | |||
51 | const char *source; | |||
52 | const char *user; | |||
53 | const char *pass; | |||
54 | Ns_Mutex lock; | |||
55 | Ns_Cond waitCond; | |||
56 | Ns_Cond getCond; | |||
57 | const char *driver; | |||
58 | struct DbDriver *driverPtr; | |||
59 | int waiting; | |||
60 | int nhandles; | |||
61 | struct Handle *firstPtr; | |||
62 | struct Handle *lastPtr; | |||
63 | Ns_Time maxidle; | |||
64 | Ns_Time maxopen; | |||
65 | Tcl_WideInt statementCount; | |||
66 | Tcl_WideInt getHandleCount; | |||
67 | Ns_Time waitTime; | |||
68 | Ns_Time sqlTime; | |||
69 | Ns_Time minDuration; | |||
70 | int stale_on_close; | |||
71 | bool_Bool fVerboseError; | |||
72 | } Pool; | |||
73 | ||||
74 | /* | |||
75 | * The following structure defines the internal | |||
76 | * state of a database handle. | |||
77 | */ | |||
78 | ||||
79 | typedef struct Handle { | |||
80 | const char *driver; | |||
81 | const char *datasource; | |||
82 | const char *user; | |||
83 | const char *password; | |||
84 | void *connection; | |||
85 | const char *poolname; | |||
86 | bool_Bool connected; | |||
87 | bool_Bool verbose; | |||
88 | Ns_Set *row; | |||
89 | char cExceptionCode[6]; | |||
90 | Ns_DStringTcl_DString dsExceptionMsg; | |||
91 | void *context; | |||
92 | void *statement; | |||
93 | bool_Bool fetchingRows; | |||
94 | /* Members above must match Ns_DbHandle */ | |||
95 | struct Handle *nextPtr; | |||
96 | struct Pool *poolPtr; | |||
97 | time_t otime; /* open time */ | |||
98 | time_t atime; /* last access time */ | |||
99 | uintptr_t sessionId; | |||
100 | Ns_Time sqlTime; | |||
101 | Tcl_WideInt statementCount; | |||
102 | int stale_on_close; | |||
103 | bool_Bool stale; | |||
104 | bool_Bool used; | |||
105 | bool_Bool active; | |||
106 | } Handle; | |||
107 | ||||
108 | /* | |||
109 | * The following structure maintains per-server data. | |||
110 | */ | |||
111 | ||||
112 | typedef struct ServData { | |||
113 | const char *defpool; | |||
114 | const char *allowed; | |||
115 | } ServData; | |||
116 | ||||
117 | const char *NS_EMPTY_STRING = ""; | |||
118 | ||||
119 | /* | |||
120 | * Local functions defined in this file | |||
121 | */ | |||
122 | ||||
123 | static Pool *GetPool(const char *pool) | |||
124 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
125 | static void ReturnHandle(Handle *handlePtr) | |||
126 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
127 | static bool_Bool IsStale(const Handle *handlePtr, time_t now) | |||
128 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
129 | static Ns_ReturnCode Connect(Handle *handlePtr) | |||
130 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
131 | static Pool *CreatePool(const char *pool, const char *path, const char *driver) | |||
132 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))); | |||
133 | static int IncrCount(const char *context, const Pool *poolPtr, int incr) | |||
134 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_NONNULL(2)__attribute__((__nonnull__(2))); | |||
135 | static ServData *GetServer(const char *server) | |||
136 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
137 | static void TransferHandleStats(Handle *handlePtr) | |||
138 | NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))); | |||
139 | ||||
140 | /* | |||
141 | * Static variables defined in this file | |||
142 | */ | |||
143 | ||||
144 | static Ns_TlsCleanup FreeTable; | |||
145 | static Ns_SchedProc CheckPool; | |||
146 | static Ns_ArgProc CheckArgProc; | |||
147 | ||||
148 | static Tcl_HashTable poolsTable; | |||
149 | static Tcl_HashTable serversTable; | |||
150 | static Ns_Tls tls; | |||
151 | static Ns_Mutex sessionMutex = NULL((void*)0); | |||
152 | ||||
153 | /* | |||
154 | *---------------------------------------------------------------------- | |||
155 | * | |||
156 | * Ns_DbPoolDescription -- | |||
157 | * | |||
158 | * Return the pool's description string. | |||
159 | * | |||
160 | * Results: | |||
161 | * Configured description string or NULL. | |||
162 | * | |||
163 | * Side effects: | |||
164 | * None. | |||
165 | * | |||
166 | *---------------------------------------------------------------------- | |||
167 | */ | |||
168 | ||||
169 | const char * | |||
170 | Ns_DbPoolDescription(const char *pool) | |||
171 | { | |||
172 | const Pool *poolPtr; | |||
173 | const char *result; | |||
174 | ||||
175 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
176 | ||||
177 | poolPtr = GetPool(pool); | |||
178 | if (poolPtr == NULL((void*)0)) { | |||
179 | result = NULL((void*)0); | |||
180 | } else { | |||
181 | result = poolPtr->desc; | |||
182 | } | |||
183 | ||||
184 | return result; | |||
185 | } | |||
186 | ||||
187 | ||||
188 | /* | |||
189 | *---------------------------------------------------------------------- | |||
190 | * | |||
191 | * Ns_DbPoolDefault -- | |||
192 | * | |||
193 | * Return the default pool. | |||
194 | * | |||
195 | * Results: | |||
196 | * String name of default pool or NULL if no default is defined. | |||
197 | * | |||
198 | * Side effects: | |||
199 | * None. | |||
200 | * | |||
201 | *---------------------------------------------------------------------- | |||
202 | */ | |||
203 | ||||
204 | const char * | |||
205 | Ns_DbPoolDefault(const char *server) | |||
206 | { | |||
207 | const ServData *sdataPtr; | |||
208 | ||||
209 | NS_NONNULL_ASSERT(server != NULL)((void) (0)); | |||
210 | ||||
211 | sdataPtr = GetServer(server); | |||
212 | return ((sdataPtr != NULL((void*)0)) ? sdataPtr->defpool : NULL((void*)0)); | |||
213 | } | |||
214 | ||||
215 | ||||
216 | /* | |||
217 | *---------------------------------------------------------------------- | |||
218 | * | |||
219 | * Ns_DbPoolList -- | |||
220 | * | |||
221 | * Return the list of all pools. | |||
222 | * | |||
223 | * Results: | |||
224 | * Double-null terminated list of pool names. | |||
225 | * | |||
226 | * Side effects: | |||
227 | * None. | |||
228 | * | |||
229 | *---------------------------------------------------------------------- | |||
230 | */ | |||
231 | ||||
232 | const char * | |||
233 | Ns_DbPoolList(const char *server) | |||
234 | { | |||
235 | const ServData *sdataPtr; | |||
236 | ||||
237 | NS_NONNULL_ASSERT(server != NULL)((void) (0)); | |||
238 | ||||
239 | sdataPtr = GetServer(server); | |||
240 | return ((sdataPtr != NULL((void*)0)) ? sdataPtr->allowed : NULL((void*)0)); | |||
241 | } | |||
242 | ||||
243 | ||||
244 | /* | |||
245 | *---------------------------------------------------------------------- | |||
246 | * | |||
247 | * Ns_DbPoolAllowable -- | |||
248 | * | |||
249 | * Check that access is allowed to a pool. | |||
250 | * | |||
251 | * Results: | |||
252 | * NS_TRUE if allowed, NS_FALSE otherwise. | |||
253 | * | |||
254 | * Side effects: | |||
255 | * None. | |||
256 | * | |||
257 | *---------------------------------------------------------------------- | |||
258 | */ | |||
259 | ||||
260 | bool_Bool | |||
261 | Ns_DbPoolAllowable(const char *server, const char *pool) | |||
262 | { | |||
263 | register const char *p; | |||
264 | bool_Bool result = NS_FALSE0; | |||
265 | ||||
266 | NS_NONNULL_ASSERT(server != NULL)((void) (0)); | |||
267 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
268 | ||||
269 | p = Ns_DbPoolList(server); | |||
270 | if (p != NULL((void*)0)) { | |||
271 | while (*p != '\0') { | |||
272 | if (STREQ(pool, p)(((*(pool)) == (*(p))) && (strcmp((pool),(p)) == 0))) { | |||
273 | result = NS_TRUE1; | |||
274 | break; | |||
275 | } | |||
276 | p = p + strlen(p) + 1; | |||
277 | } | |||
278 | } | |||
279 | return result; | |||
280 | } | |||
281 | ||||
282 | ||||
283 | /* | |||
284 | *---------------------------------------------------------------------- | |||
285 | * | |||
286 | * Ns_DbPoolPutHandle -- | |||
287 | * | |||
288 | * Cleanup and then return a handle to its pool. | |||
289 | * | |||
290 | * Results: | |||
291 | * None. | |||
292 | * | |||
293 | * Side effects: | |||
294 | * Handle is flushed, reset, and possibly closed as required. | |||
295 | * | |||
296 | *---------------------------------------------------------------------- | |||
297 | */ | |||
298 | ||||
299 | void | |||
300 | Ns_DbPoolPutHandle(Ns_DbHandle *handle) | |||
301 | { | |||
302 | Handle *handlePtr; | |||
303 | Pool *poolPtr; | |||
304 | time_t now; | |||
305 | ||||
306 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
307 | ||||
308 | handlePtr = (Handle *) handle; | |||
309 | poolPtr = handlePtr->poolPtr; | |||
310 | ||||
311 | /* | |||
312 | * Cleanup the handle. | |||
313 | */ | |||
314 | ||||
315 | (void) Ns_DbFlush(handle); | |||
316 | (void) Ns_DbResetHandle(handle); | |||
317 | ||||
318 | Ns_DStringFreeTcl_DStringFree(&handle->dsExceptionMsg); | |||
319 | handle->cExceptionCode[0] = '\0'; | |||
320 | handlePtr->active = NS_FALSE0; | |||
321 | ||||
322 | /* | |||
323 | * Close the handle if it is stale, otherwise update | |||
324 | * the last access time. | |||
325 | */ | |||
326 | ||||
327 | time(&now); | |||
328 | if (IsStale(handlePtr, now) == NS_TRUE1) { | |||
| ||||
329 | NsDbDisconnect(handle); | |||
330 | } else { | |||
331 | handlePtr->atime = now; | |||
332 | } | |||
333 | (void) IncrCount("Ns_DbPoolPutHandle", poolPtr, -1); | |||
334 | ||||
335 | Ns_MutexLock(&poolPtr->lock); | |||
336 | TransferHandleStats(handlePtr); | |||
337 | ReturnHandle(handlePtr); | |||
338 | if (poolPtr->waiting != 0) { | |||
339 | Ns_CondSignal(&poolPtr->getCond); | |||
340 | } | |||
341 | Ns_MutexUnlock(&poolPtr->lock); | |||
342 | } | |||
343 | ||||
344 | ||||
345 | /* | |||
346 | *---------------------------------------------------------------------- | |||
347 | * | |||
348 | * Ns_DbPoolTimedGetHandle -- | |||
349 | * | |||
350 | * Return a single handle from a pool within the given number of | |||
351 | * seconds. | |||
352 | * | |||
353 | * Results: | |||
354 | * Pointer to Ns_DbHandle or NULL on error or timeout. | |||
355 | * | |||
356 | * Side effects: | |||
357 | * Database may be opened if needed. | |||
358 | * | |||
359 | *---------------------------------------------------------------------- | |||
360 | */ | |||
361 | ||||
362 | Ns_DbHandle * | |||
363 | Ns_DbPoolTimedGetHandle(const char *pool, const Ns_Time *wait) | |||
364 | { | |||
365 | Ns_DbHandle *handle; | |||
366 | ||||
367 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
368 | ||||
369 | if (Ns_DbPoolTimedGetMultipleHandles(&handle, pool, 1, wait) != NS_OK) { | |||
370 | handle = NULL((void*)0); | |||
371 | } | |||
372 | return handle; | |||
373 | } | |||
374 | ||||
375 | ||||
376 | /* | |||
377 | *---------------------------------------------------------------------- | |||
378 | * | |||
379 | * Ns_DbPoolGetHandle -- | |||
380 | * | |||
381 | * Return a single handle from a pool. | |||
382 | * | |||
383 | * Results: | |||
384 | * Pointer to Ns_DbHandle or NULL on error. | |||
385 | * | |||
386 | * Side effects: | |||
387 | * Database may be opened if needed. | |||
388 | * | |||
389 | *---------------------------------------------------------------------- | |||
390 | */ | |||
391 | ||||
392 | Ns_DbHandle * | |||
393 | Ns_DbPoolGetHandle(const char *pool) | |||
394 | { | |||
395 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
396 | ||||
397 | return Ns_DbPoolTimedGetHandle(pool, NULL((void*)0)); | |||
398 | } | |||
399 | ||||
400 | ||||
401 | /* | |||
402 | *---------------------------------------------------------------------- | |||
403 | * | |||
404 | * Ns_DbPoolGetMultipleHandles -- | |||
405 | * | |||
406 | * Return 1 or more handles from a pool. | |||
407 | * | |||
408 | * Results: | |||
409 | * NS_OK if the handlers where allocated, NS_ERROR | |||
410 | * otherwise. | |||
411 | * | |||
412 | * Side effects: | |||
413 | * Given array of handles is updated with pointers to allocated | |||
414 | * handles. Also, database may be opened if needed. | |||
415 | * | |||
416 | *---------------------------------------------------------------------- | |||
417 | */ | |||
418 | ||||
419 | Ns_ReturnCode | |||
420 | Ns_DbPoolGetMultipleHandles(Ns_DbHandle **handles, const char *pool, int nwant) | |||
421 | { | |||
422 | NS_NONNULL_ASSERT(handles != NULL)((void) (0)); | |||
423 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
424 | ||||
425 | return Ns_DbPoolTimedGetMultipleHandles(handles, pool, nwant, NULL((void*)0)); | |||
426 | } | |||
427 | ||||
428 | ||||
429 | /* | |||
430 | *---------------------------------------------------------------------- | |||
431 | * | |||
432 | * Ns_DbPoolTimedGetMultipleHandles -- | |||
433 | * | |||
434 | * Return 1 or more handles from a pool within the given number | |||
435 | * of seconds. | |||
436 | * | |||
437 | * Results: | |||
438 | * NS_OK if the handlers where allocated, NS_TIMEOUT if the | |||
439 | * thread could not wait long enough for the handles, NS_ERROR | |||
440 | * otherwise. | |||
441 | * | |||
442 | * Side effects: | |||
443 | * Given array of handles is updated with pointers to allocated | |||
444 | * handles. Also, database may be opened if needed. | |||
445 | * | |||
446 | *---------------------------------------------------------------------- | |||
447 | */ | |||
448 | ||||
449 | Ns_ReturnCode | |||
450 | Ns_DbPoolTimedGetMultipleHandles(Ns_DbHandle **handles, const char *pool, | |||
451 | int nwant, const Ns_Time *wait) | |||
452 | { | |||
453 | Handle *handlePtr; | |||
454 | Handle **handlesPtrPtr = (Handle **) handles; | |||
455 | Pool *poolPtr; | |||
456 | Ns_Time timeout, startTime, endTime, diffTime; | |||
457 | const Ns_Time *timePtr; | |||
458 | int i, ngot; | |||
459 | Ns_ReturnCode status; | |||
460 | ||||
461 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
462 | NS_NONNULL_ASSERT(handles != NULL)((void) (0)); | |||
463 | ||||
464 | /* | |||
465 | * Verify the pool, the number of available handles in the pool, | |||
466 | * and that the calling thread does not already own handles from | |||
467 | * this pool. | |||
468 | */ | |||
469 | ||||
470 | poolPtr = GetPool(pool); | |||
471 | if (poolPtr == NULL((void*)0)) { | |||
472 | Ns_Log(Error, "dbinit: no such pool '%s'", pool); | |||
473 | return NS_ERROR; | |||
474 | } | |||
475 | if (poolPtr->nhandles < nwant) { | |||
476 | Ns_Log(Error, "dbinit: " | |||
477 | "failed to get %d handles from a db pool of only %d handles: '%s'", | |||
478 | nwant, poolPtr->nhandles, pool); | |||
479 | return NS_ERROR; | |||
480 | } | |||
481 | ngot = IncrCount("Ns_DbPoolTimedGetMultipleHandles try", poolPtr, nwant); | |||
482 | if (ngot > 0) { | |||
483 | Ns_Log(Error, "dbinit: db handle limit exceeded: " | |||
484 | "thread already owns %d handle%s from pool '%s'", | |||
485 | ngot, ngot == 1 ? NS_EMPTY_STRING : "s", pool); | |||
486 | (void) IncrCount("Ns_DbPoolTimedGetMultipleHandles fail", poolPtr, -nwant); | |||
487 | return NS_ERROR; | |||
488 | } | |||
489 | ||||
490 | /* | |||
491 | * Wait until this thread can be the exclusive thread acquiring | |||
492 | * handles and then wait until all requested handles are available, | |||
493 | * watching for timeout in either of these waits. | |||
494 | */ | |||
495 | Ns_GetTime(&startTime); | |||
496 | if (wait == NULL((void*)0)) { | |||
497 | timePtr = NULL((void*)0); | |||
498 | } else { | |||
499 | Ns_GetTime(&timeout); | |||
500 | Ns_IncrTime(&timeout, wait->sec, wait->usec); | |||
501 | timePtr = &timeout; | |||
502 | } | |||
503 | status = NS_OK; | |||
504 | ||||
505 | Ns_MutexLock(&poolPtr->lock); | |||
506 | while (status == NS_OK && poolPtr->waiting != 0) { | |||
507 | status = Ns_CondTimedWait(&poolPtr->waitCond, &poolPtr->lock, timePtr); | |||
508 | } | |||
509 | if (status == NS_OK) { | |||
510 | poolPtr->waiting = 1; | |||
511 | while (status == NS_OK && ngot < nwant) { | |||
512 | while (status == NS_OK && poolPtr->firstPtr == NULL((void*)0)) { | |||
513 | status = Ns_CondTimedWait(&poolPtr->getCond, &poolPtr->lock, | |||
514 | timePtr); | |||
515 | } | |||
516 | if (poolPtr->firstPtr != NULL((void*)0)) { | |||
517 | handlePtr = poolPtr->firstPtr; | |||
518 | poolPtr->firstPtr = handlePtr->nextPtr; | |||
519 | handlePtr->nextPtr = NULL((void*)0); | |||
520 | if (poolPtr->lastPtr == handlePtr) { | |||
521 | poolPtr->lastPtr = NULL((void*)0); | |||
522 | } | |||
523 | handlePtr->used = NS_TRUE1; | |||
524 | handlesPtrPtr[ngot++] = handlePtr; | |||
525 | } | |||
526 | } | |||
527 | poolPtr->waiting = 0; | |||
528 | Ns_CondSignal(&poolPtr->waitCond); | |||
529 | } | |||
530 | Ns_MutexUnlock(&poolPtr->lock); | |||
531 | ||||
532 | /* | |||
533 | * Handle special race condition where the final requested handle | |||
534 | * arrived just as the condition wait was timing out. | |||
535 | */ | |||
536 | ||||
537 | if (status == NS_TIMEOUT && ngot == nwant) { | |||
538 | status = NS_OK; | |||
539 | } | |||
540 | ||||
541 | /* | |||
542 | * If status is still ok, connect any handles not already connected, | |||
543 | * otherwise return any allocated handles back to the pool, then | |||
544 | * update the final number of handles owned by this thread. | |||
545 | */ | |||
546 | ||||
547 | for (i = 0; status == NS_OK && i < ngot; ++i) { | |||
548 | handlePtr = handlesPtrPtr[i]; | |||
549 | if (!handlePtr->connected) { | |||
550 | status = Connect(handlePtr); | |||
551 | } | |||
552 | } | |||
553 | ||||
554 | Ns_GetTime(&endTime); | |||
555 | (void)Ns_DiffTime(&endTime, &startTime, &diffTime); | |||
556 | ||||
557 | Ns_MutexLock(&poolPtr->lock); | |||
558 | if (status != NS_OK) { | |||
559 | while (ngot > 0) { | |||
560 | ReturnHandle(handlesPtrPtr[--ngot]); | |||
561 | } | |||
562 | if (poolPtr->waiting != 0) { | |||
563 | Ns_CondSignal(&poolPtr->getCond); | |||
564 | } | |||
565 | (void) IncrCount("Ns_DbPoolTimedGetMultipleHandles fail2", poolPtr, -nwant); | |||
566 | } | |||
567 | ||||
568 | Ns_IncrTime(&poolPtr->waitTime, diffTime.sec, diffTime.usec); | |||
569 | poolPtr->getHandleCount++; | |||
570 | Ns_MutexUnlock(&poolPtr->lock); | |||
571 | ||||
572 | return status; | |||
573 | } | |||
574 | ||||
575 | ||||
576 | /* | |||
577 | *---------------------------------------------------------------------- | |||
578 | * | |||
579 | * Ns_DbBouncePool -- | |||
580 | * | |||
581 | * Close all handles in the pool. | |||
582 | * Marks handles as stale and close these via CheckPool(). | |||
583 | * | |||
584 | * Results: | |||
585 | * NS_OK if pool was in use, NS_ERROR otherwise. | |||
586 | * | |||
587 | * Side effects: | |||
588 | * Closing handles. | |||
589 | * | |||
590 | *---------------------------------------------------------------------- | |||
591 | */ | |||
592 | ||||
593 | Ns_ReturnCode | |||
594 | Ns_DbBouncePool(const char *pool) | |||
595 | { | |||
596 | Pool *poolPtr; | |||
597 | Handle *handlePtr; | |||
598 | Ns_ReturnCode status = NS_OK; | |||
599 | ||||
600 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
601 | ||||
602 | poolPtr = GetPool(pool); | |||
603 | if (poolPtr == NULL((void*)0)) { | |||
604 | status = NS_ERROR; | |||
605 | ||||
606 | } else { | |||
607 | Ns_MutexLock(&poolPtr->lock); | |||
608 | poolPtr->stale_on_close++; | |||
609 | handlePtr = poolPtr->firstPtr; | |||
610 | while (handlePtr != NULL((void*)0)) { | |||
611 | if (handlePtr->connected) { | |||
612 | handlePtr->stale = NS_TRUE1; | |||
613 | } | |||
614 | handlePtr->stale_on_close = poolPtr->stale_on_close; | |||
615 | handlePtr = handlePtr->nextPtr; | |||
616 | } | |||
617 | Ns_MutexUnlock(&poolPtr->lock); | |||
618 | CheckPool(poolPtr, 0); | |||
619 | } | |||
620 | return status; | |||
621 | } | |||
622 | ||||
623 | ||||
624 | /* | |||
625 | *---------------------------------------------------------------------- | |||
626 | * | |||
627 | * NsDbInitPools -- | |||
628 | * | |||
629 | * Initialize the database pools at startup. | |||
630 | * | |||
631 | * Results: | |||
632 | * None. | |||
633 | * | |||
634 | * Side effects: | |||
635 | * Pools may be created as configured. | |||
636 | * | |||
637 | *---------------------------------------------------------------------- | |||
638 | */ | |||
639 | ||||
640 | void | |||
641 | NsDbInitPools(void) | |||
642 | { | |||
643 | const Pool *poolPtr; | |||
644 | const Ns_Set *pools; | |||
645 | const char *path, *driver; | |||
646 | int isNew; | |||
647 | size_t i; | |||
648 | ||||
649 | Ns_TlsAlloc(&tls, FreeTable); | |||
650 | ||||
651 | /* | |||
652 | * Provide a name for the lock when it is not yet initialized. | |||
653 | */ | |||
654 | if (sessionMutex == NULL((void*)0)) { | |||
655 | Ns_MutexInit(&sessionMutex); | |||
656 | Ns_MutexSetName(&sessionMutex, "nsdb:session"); | |||
657 | } | |||
658 | ||||
659 | /* | |||
660 | * Attempt to create each database pool. | |||
661 | */ | |||
662 | ||||
663 | Tcl_InitHashTable(&serversTable, TCL_STRING_KEYS(0)); | |||
664 | Tcl_InitHashTable(&poolsTable, TCL_STRING_KEYS(0)); | |||
665 | pools = Ns_ConfigGetSection("ns/db/pools"); | |||
666 | ||||
667 | for (i = 0u; (pools != NULL((void*)0)) && (i < Ns_SetSize(pools)((pools)->size)); ++i) { | |||
668 | const char *pool = Ns_SetKey(pools, i)((pools)->fields[(i)].name); | |||
669 | Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&poolsTable, pool, &isNew)(*((&poolsTable)->createProc))(&poolsTable, (const char *)(pool), &isNew); | |||
670 | ||||
671 | Ns_Log(Ns_LogSqlDebug, "nsdb: Add DB pool: %s", pool); | |||
672 | if (isNew == 0) { | |||
673 | Ns_Log(Error, "dbinit: duplicate pool: %s", pool); | |||
674 | continue; | |||
675 | } | |||
676 | path = Ns_ConfigSectionPath(NULL((void*)0), NULL((void*)0), NULL((void*)0), "db", "pool", pool, (char *)0L); | |||
677 | driver = Ns_ConfigGetValue(path, "driver"); | |||
678 | poolPtr = CreatePool(pool, path, driver); | |||
679 | if (poolPtr == NULL((void*)0)) { | |||
680 | Tcl_DeleteHashEntry(hPtr); | |||
681 | } else { | |||
682 | Tcl_SetHashValue(hPtr, poolPtr)((hPtr)->clientData = (ClientData) (poolPtr)); | |||
683 | } | |||
684 | } | |||
685 | Ns_RegisterProcInfo((ns_funcptr_t)CheckPool, "nsdb:check", CheckArgProc); | |||
686 | } | |||
687 | ||||
688 | ||||
689 | /* | |||
690 | *---------------------------------------------------------------------- | |||
691 | * | |||
692 | * Ns_DbPoolStats -- | |||
693 | * | |||
694 | * return usage statistics from pools | |||
695 | * | |||
696 | * Results: | |||
697 | * Tcl result code. | |||
698 | * | |||
699 | * Side effects: | |||
700 | * None. | |||
701 | * | |||
702 | *---------------------------------------------------------------------- | |||
703 | */ | |||
704 | int | |||
705 | Ns_DbPoolStats(Tcl_Interp *interp) | |||
706 | { | |||
707 | const Ns_Set *pools; | |||
708 | size_t i; | |||
709 | Tcl_Obj *resultObj; | |||
710 | int result = TCL_OK0; | |||
711 | ||||
712 | NS_NONNULL_ASSERT(interp != NULL)((void) (0)); | |||
713 | ||||
714 | resultObj = Tcl_NewListObj(0, NULL((void*)0)); | |||
715 | pools = Ns_ConfigGetSection("ns/db/pools"); | |||
716 | ||||
717 | for (i = 0u; (pools != NULL((void*)0)) && (i < Ns_SetSize(pools)((pools)->size)); ++i) { | |||
718 | const char *pool = Ns_SetKey(pools, i)((pools)->fields[(i)].name); | |||
719 | Pool *poolPtr; | |||
720 | ||||
721 | poolPtr = GetPool(pool); | |||
722 | if (poolPtr == NULL((void*)0)) { | |||
723 | Ns_Log(Warning, "Ignore invalid pool: %s", pool); | |||
724 | } else { | |||
725 | Handle *handlePtr; | |||
726 | Tcl_Obj *valuesObj; | |||
727 | int unused = 0, connected = 0, len; | |||
728 | char buf[100]; | |||
729 | Tcl_WideInt statementCount, getHandleCount; | |||
730 | Ns_Time sqlTime, waitTime; | |||
731 | ||||
732 | /* | |||
733 | * Iterate over the handles of this pool. Some of the | |||
734 | * currently unused handles might have been never used. By | |||
735 | * subtracting the never used handles from the total | |||
736 | * handles, we determine the used handles. | |||
737 | */ | |||
738 | Ns_MutexLock(&poolPtr->lock); | |||
739 | for (handlePtr = poolPtr->firstPtr; handlePtr != NULL((void*)0); handlePtr = handlePtr->nextPtr) { | |||
740 | if (!handlePtr->used) { | |||
741 | unused ++; | |||
742 | } | |||
743 | if (handlePtr->connected) { | |||
744 | connected ++; | |||
745 | } | |||
746 | TransferHandleStats(handlePtr); | |||
747 | } | |||
748 | statementCount = poolPtr->statementCount; | |||
749 | getHandleCount = poolPtr->getHandleCount; | |||
750 | sqlTime = poolPtr->sqlTime; | |||
751 | waitTime = poolPtr->waitTime; | |||
752 | Ns_MutexUnlock(&poolPtr->lock); | |||
753 | ||||
754 | valuesObj = Tcl_NewListObj(0, NULL((void*)0)); | |||
755 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("statements", 10)); | |||
756 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
757 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewWideIntObj(statementCount)); | |||
758 | } | |||
759 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
760 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("gethandles", 10)); | |||
761 | } | |||
762 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
763 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewWideIntObj(getHandleCount)); | |||
764 | } | |||
765 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
766 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("handles", 7)); | |||
767 | } | |||
768 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
769 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(poolPtr->nhandles)); | |||
770 | } | |||
771 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
772 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("connected", 9)); | |||
773 | } | |||
774 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
775 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(connected)); | |||
776 | } | |||
777 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
778 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("used", 4)); | |||
779 | } | |||
780 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
781 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewIntObj(poolPtr->nhandles - unused)); | |||
782 | } | |||
783 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
784 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("waittime", 8)); | |||
785 | } | |||
786 | /* | |||
787 | * We could use Ns_TclNewTimeObj here (2x), when the default representation | |||
788 | * of the obj would be floating point format, but we have still sec:usec. | |||
789 | * | |||
790 | * Tcl_ListObjAppendElement(interp, valuesObj, Ns_TclNewTimeObj(&poolPtr->waitTime)); | |||
791 | */ | |||
792 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
793 | len = snprintf(buf, sizeof(buf), NS_TIME_FMT, (int64_t)waitTime.sec, waitTime.usec)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size (buf, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)waitTime.sec , waitTime.usec); | |||
794 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj(buf, len)); | |||
795 | } | |||
796 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
797 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj("sqltime", 7)); | |||
798 | } | |||
799 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
800 | len = snprintf(buf, sizeof(buf), NS_TIME_FMT, (int64_t)sqlTime.sec, sqlTime.usec)__builtin___snprintf_chk (buf, sizeof(buf), 2 - 1, __builtin_object_size (buf, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)sqlTime.sec, sqlTime.usec); | |||
801 | result = Tcl_ListObjAppendElement(interp, valuesObj, Tcl_NewStringObj(buf, len)); | |||
802 | } | |||
803 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
804 | result = Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(pool, -1)); | |||
805 | } | |||
806 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
807 | result = Tcl_ListObjAppendElement(interp, resultObj, valuesObj); | |||
808 | } | |||
809 | if (unlikely(result != TCL_OK)(__builtin_expect((result != 0), 0))) { | |||
810 | break; | |||
811 | } | |||
812 | } | |||
813 | } | |||
814 | if (likely(result == TCL_OK)(__builtin_expect((result == 0), 1))) { | |||
815 | Tcl_SetObjResult(interp, resultObj); | |||
816 | } | |||
817 | ||||
818 | return result; | |||
819 | } | |||
820 | ||||
821 | ||||
822 | ||||
823 | /* | |||
824 | *---------------------------------------------------------------------- | |||
825 | * | |||
826 | * NsDbInitServer -- | |||
827 | * | |||
828 | * Initialize a virtual server allowed and default options. | |||
829 | * | |||
830 | * Results: | |||
831 | * None. | |||
832 | * | |||
833 | * Side effects: | |||
834 | * None. | |||
835 | * | |||
836 | *---------------------------------------------------------------------- | |||
837 | */ | |||
838 | ||||
839 | void | |||
840 | NsDbInitServer(const char *server) | |||
841 | { | |||
842 | ServData *sdataPtr; | |||
843 | Tcl_HashEntry *hPtr; | |||
844 | Tcl_HashSearch search; | |||
845 | const char *path, *pool; | |||
846 | Ns_DStringTcl_DString ds; | |||
847 | int isNew; | |||
848 | ||||
849 | path = Ns_ConfigSectionPath(NULL((void*)0), server, NULL((void*)0), "db", (char *)0L); | |||
850 | ||||
851 | /* | |||
852 | * Verify the default pool exists, if any. | |||
853 | */ | |||
854 | ||||
855 | sdataPtr = ns_malloc(sizeof(ServData)); | |||
856 | hPtr = Tcl_CreateHashEntry(&serversTable, server, &isNew)(*((&serversTable)->createProc))(&serversTable, (const char *)(server), &isNew); | |||
857 | Tcl_SetHashValue(hPtr, sdataPtr)((hPtr)->clientData = (ClientData) (sdataPtr)); | |||
858 | sdataPtr->defpool = Ns_ConfigGetValue(path, "defaultpool"); | |||
859 | if (sdataPtr->defpool != NULL((void*)0) && | |||
860 | (Tcl_FindHashEntry(&poolsTable, sdataPtr->defpool)(*((&poolsTable)->findProc))(&poolsTable, (const char *)(sdataPtr->defpool)) == NULL((void*)0))) { | |||
861 | Ns_Log(Error, "dbinit: no such default pool '%s'", sdataPtr->defpool); | |||
862 | sdataPtr->defpool = NULL((void*)0); | |||
863 | } | |||
864 | ||||
865 | /* | |||
866 | * Construct the allowed list and call the server-specific init. | |||
867 | */ | |||
868 | ||||
869 | sdataPtr->allowed = NS_EMPTY_STRING; | |||
870 | pool = Ns_ConfigGetValue(path, "pools"); | |||
871 | if (pool != NULL((void*)0) && poolsTable.numEntries > 0) { | |||
872 | const Pool *poolPtr; | |||
873 | char *allowed; | |||
874 | ||||
875 | Ns_DStringInitTcl_DStringInit(&ds); | |||
876 | if (STREQ(pool, "*")(((*(pool)) == (*("*"))) && (strcmp((pool),("*")) == 0 ))) { | |||
877 | hPtr = Tcl_FirstHashEntry(&poolsTable, &search); | |||
878 | while (hPtr != NULL((void*)0)) { | |||
879 | poolPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData); | |||
880 | NsDbDriverInit(server, poolPtr->driverPtr); | |||
881 | Ns_DStringAppendArg(&ds, poolPtr->name); | |||
882 | hPtr = Tcl_NextHashEntry(&search); | |||
883 | } | |||
884 | } else { | |||
885 | char *p, *toDelete, *pool2; | |||
886 | ||||
887 | toDelete = p = pool2 = ns_strdup(pool); | |||
888 | while (p != NULL((void*)0) && *p != '\0') { | |||
889 | p = strchr(pool2, INTCHAR(',')((int)((unsigned char)((','))))); | |||
890 | if (p != NULL((void*)0)) { | |||
891 | *p = '\0'; | |||
892 | } | |||
893 | hPtr = Tcl_FindHashEntry(&poolsTable, pool2)(*((&poolsTable)->findProc))(&poolsTable, (const char *)(pool2)); | |||
894 | if (hPtr != NULL((void*)0)) { | |||
895 | poolPtr = Tcl_GetHashValue(hPtr)((hPtr)->clientData); | |||
896 | NsDbDriverInit(server, poolPtr->driverPtr); | |||
897 | Ns_DStringAppendArg(&ds, poolPtr->name); | |||
898 | } | |||
899 | if (p != NULL((void*)0)) { | |||
900 | *p++ = ','; | |||
901 | } | |||
902 | pool2 = p; | |||
903 | } | |||
904 | ns_free(toDelete); | |||
905 | } | |||
906 | allowed = ns_malloc((size_t)ds.length + 1u); | |||
907 | memcpy(allowed, ds.string, (size_t)ds.length + 1u); | |||
908 | sdataPtr->allowed = allowed; | |||
909 | Ns_DStringFreeTcl_DStringFree(&ds); | |||
910 | } | |||
911 | } | |||
912 | ||||
913 | ||||
914 | /* | |||
915 | *---------------------------------------------------------------------- | |||
916 | * | |||
917 | * NsDbDisconnect -- | |||
918 | * | |||
919 | * Disconnect a handle by closing the database if needed. | |||
920 | * | |||
921 | * Results: | |||
922 | * None. | |||
923 | * | |||
924 | * Side effects: | |||
925 | * None. | |||
926 | * | |||
927 | *---------------------------------------------------------------------- | |||
928 | */ | |||
929 | ||||
930 | void | |||
931 | NsDbDisconnect(Ns_DbHandle *handle) | |||
932 | { | |||
933 | Handle *handlePtr; | |||
934 | ||||
935 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
936 | ||||
937 | handlePtr = (Handle *) handle; | |||
938 | (void)NsDbClose(handle); | |||
939 | ||||
940 | handlePtr->connected = NS_FALSE0; | |||
941 | handlePtr->atime = handlePtr->otime = 0; | |||
942 | handlePtr->active = NS_FALSE0; | |||
943 | handlePtr->stale = NS_FALSE0; | |||
944 | } | |||
945 | ||||
946 | ||||
947 | /* | |||
948 | *---------------------------------------------------------------------- | |||
949 | * | |||
950 | * NsDbGetActive, NsDbSetActive -- | |||
951 | * | |||
952 | * Query or modify the "active" state of a handle. A handle is | |||
953 | * active between a "ns_db select" and the last "ns_db getrow" | |||
954 | * statement. | |||
955 | * | |||
956 | * Results: | |||
957 | * Boolean activity state | |||
958 | * | |||
959 | * Side effects: | |||
960 | * None. | |||
961 | * | |||
962 | *---------------------------------------------------------------------- | |||
963 | */ | |||
964 | bool_Bool | |||
965 | NsDbGetActive(Ns_DbHandle *handle) | |||
966 | { | |||
967 | Handle *handlePtr = (Handle *) handle; | |||
968 | ||||
969 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
970 | ||||
971 | return handlePtr->active; | |||
972 | } | |||
973 | ||||
974 | void | |||
975 | NsDbSetActive(const char *UNUSED(context)UNUSED_context __attribute__((__unused__)), Ns_DbHandle *handle, bool_Bool active) | |||
976 | { | |||
977 | Handle *handlePtr = (Handle *) handle; | |||
978 | ||||
979 | /*NS_NONNULL_ASSERT(context != NULL);*/ | |||
980 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
981 | ||||
982 | handlePtr->active = active; | |||
983 | } | |||
984 | ||||
985 | ||||
986 | ||||
987 | /* | |||
988 | *---------------------------------------------------------------------- | |||
989 | * | |||
990 | * NsDbLogSql -- | |||
991 | * | |||
992 | * Log a SQL statement depending on the verbose state of the | |||
993 | * handle. | |||
994 | * | |||
995 | * Results: | |||
996 | * None. | |||
997 | * | |||
998 | * Side effects: | |||
999 | * None. | |||
1000 | * | |||
1001 | *---------------------------------------------------------------------- | |||
1002 | */ | |||
1003 | ||||
1004 | void | |||
1005 | NsDbLogSql(const Ns_Time *startTime, Ns_DbHandle *handle, const char *sql) | |||
1006 | { | |||
1007 | Pool *poolPtr; | |||
1008 | Handle *handlePtr; | |||
1009 | ||||
1010 | NS_NONNULL_ASSERT(startTime != NULL)((void) (0)); | |||
1011 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
1012 | NS_NONNULL_ASSERT(sql != NULL)((void) (0)); | |||
1013 | ||||
1014 | handlePtr = (Handle *)handle; | |||
1015 | poolPtr = handlePtr->poolPtr; | |||
1016 | handlePtr->statementCount++; | |||
1017 | ||||
1018 | if (handle->dsExceptionMsg.length > 0) { | |||
1019 | /* | |||
1020 | * An exception occurred. | |||
1021 | */ | |||
1022 | if (poolPtr->fVerboseError) { | |||
1023 | Ns_Log(Error, "dbinit: source %s msg '%s' SQL:\n%s", | |||
1024 | handle->datasource, handle->dsExceptionMsg.string, sql); | |||
1025 | } | |||
1026 | } else { | |||
1027 | /* | |||
1028 | * No exception occurred. | |||
1029 | */ | |||
1030 | Ns_Time endTime, diffTime; | |||
1031 | long delta; | |||
1032 | ||||
1033 | /* | |||
1034 | * Update SQL statistics. | |||
1035 | */ | |||
1036 | Ns_GetTime(&endTime); | |||
1037 | delta = Ns_DiffTime(&endTime, startTime, &diffTime); | |||
1038 | if (likely(delta >= 0)(__builtin_expect((delta >= 0), 1))) { | |||
1039 | Ns_IncrTime(&handlePtr->sqlTime, diffTime.sec, diffTime.usec); | |||
1040 | } else { | |||
1041 | Ns_Log(Warning, "negative runtime pool %s duration " NS_TIME_FMT"%" "l" "d" ".%06ld" " secs: '%s'", | |||
1042 | handle->poolname, (int64_t)diffTime.sec, diffTime.usec, sql); | |||
1043 | } | |||
1044 | ||||
1045 | /* | |||
1046 | * Log entry, when SQL debug is enabled and SQL time is above | |||
1047 | * logging threshold. | |||
1048 | */ | |||
1049 | if (Ns_LogSeverityEnabled(Ns_LogSqlDebug) == NS_TRUE1) { | |||
1050 | delta = Ns_DiffTime(&poolPtr->minDuration, &diffTime, NULL((void*)0)); | |||
1051 | ||||
1052 | if (delta < 1) { | |||
1053 | Ns_Log(Ns_LogSqlDebug, "pool %s duration " NS_TIME_FMT"%" "l" "d" ".%06ld" " secs: '%s'", | |||
1054 | handle->poolname, (int64_t)diffTime.sec, diffTime.usec, sql); | |||
1055 | } | |||
1056 | } | |||
1057 | } | |||
1058 | ||||
1059 | } | |||
1060 | ||||
1061 | ||||
1062 | /* | |||
1063 | *---------------------------------------------------------------------- | |||
1064 | * | |||
1065 | * NsDbGetDriver -- | |||
1066 | * | |||
1067 | * Return a pointer to the driver structure for a handle. | |||
1068 | * | |||
1069 | * Results: | |||
1070 | * Pointer to driver or NULL on error. | |||
1071 | * | |||
1072 | * Side effects: | |||
1073 | * None. | |||
1074 | * | |||
1075 | *---------------------------------------------------------------------- | |||
1076 | */ | |||
1077 | ||||
1078 | struct DbDriver * | |||
1079 | NsDbGetDriver(const Ns_DbHandle *handle) | |||
1080 | { | |||
1081 | struct DbDriver *result; | |||
1082 | const Handle *handlePtr = (const Handle *) handle; | |||
1083 | ||||
1084 | if (handlePtr != NULL((void*)0) && handlePtr->poolPtr != NULL((void*)0)) { | |||
1085 | result = handlePtr->poolPtr->driverPtr; | |||
1086 | } else { | |||
1087 | result = NULL((void*)0); | |||
1088 | } | |||
1089 | ||||
1090 | return result; | |||
1091 | } | |||
1092 | ||||
1093 | ||||
1094 | /* | |||
1095 | *---------------------------------------------------------------------- | |||
1096 | * | |||
1097 | * GetPool -- | |||
1098 | * | |||
1099 | * Return the Pool structure for the given pool name. | |||
1100 | * | |||
1101 | * Results: | |||
1102 | * Pointer to Pool structure or NULL if pool does not exist. | |||
1103 | * | |||
1104 | * Side effects: | |||
1105 | * None. | |||
1106 | * | |||
1107 | *---------------------------------------------------------------------- | |||
1108 | */ | |||
1109 | ||||
1110 | static Pool * | |||
1111 | GetPool(const char *pool) | |||
1112 | { | |||
1113 | Pool * result; | |||
1114 | const Tcl_HashEntry *hPtr; | |||
1115 | ||||
1116 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
1117 | ||||
1118 | hPtr = Tcl_FindHashEntry(&poolsTable, pool)(*((&poolsTable)->findProc))(&poolsTable, (const char *)(pool)); | |||
1119 | if (hPtr == NULL((void*)0)) { | |||
1120 | result = NULL((void*)0); | |||
1121 | } else { | |||
1122 | result = (Pool *) Tcl_GetHashValue(hPtr)((hPtr)->clientData); | |||
1123 | } | |||
1124 | ||||
1125 | return result; | |||
1126 | } | |||
1127 | ||||
1128 | ||||
1129 | /* | |||
1130 | *---------------------------------------------------------------------- | |||
1131 | * | |||
1132 | * ReturnHandle -- | |||
1133 | * | |||
1134 | * Return a handle to its pool. Connected handles are pushed on | |||
1135 | * the front of the list, disconnected handles are appended to the | |||
1136 | * end. | |||
1137 | * | |||
1138 | * Results: | |||
1139 | * None. | |||
1140 | * | |||
1141 | * Side effects: | |||
1142 | * Handle is returned to the pool. Note: The pool lock must be | |||
1143 | * held by the caller and this function does not signal a thread | |||
1144 | * waiting for handles. | |||
1145 | * | |||
1146 | *---------------------------------------------------------------------- | |||
1147 | */ | |||
1148 | ||||
1149 | static void | |||
1150 | ReturnHandle(Handle *handlePtr) | |||
1151 | { | |||
1152 | Pool *poolPtr; | |||
1153 | ||||
1154 | NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0)); | |||
1155 | ||||
1156 | poolPtr = handlePtr->poolPtr; | |||
1157 | if (poolPtr->firstPtr == NULL((void*)0)) { | |||
1158 | poolPtr->firstPtr = poolPtr->lastPtr = handlePtr; | |||
1159 | handlePtr->nextPtr = NULL((void*)0); | |||
1160 | } else if (handlePtr->connected) { | |||
1161 | handlePtr->nextPtr = poolPtr->firstPtr; | |||
1162 | poolPtr->firstPtr = handlePtr; | |||
1163 | } else { | |||
1164 | poolPtr->lastPtr->nextPtr = handlePtr; | |||
1165 | poolPtr->lastPtr = handlePtr; | |||
1166 | handlePtr->nextPtr = NULL((void*)0); | |||
1167 | } | |||
1168 | } | |||
1169 | ||||
1170 | ||||
1171 | /* | |||
1172 | *---------------------------------------------------------------------- | |||
1173 | * | |||
1174 | * IsStale -- | |||
1175 | * | |||
1176 | * Check to see if a handle is stale. | |||
1177 | * | |||
1178 | * Results: | |||
1179 | * NS_TRUE if handle stale, NS_FALSE otherwise. | |||
1180 | * | |||
1181 | * Side effects: | |||
1182 | * None. | |||
1183 | * | |||
1184 | *---------------------------------------------------------------------- | |||
1185 | */ | |||
1186 | ||||
1187 | static bool_Bool | |||
1188 | IsStale(const Handle *handlePtr, time_t now) | |||
1189 | { | |||
1190 | bool_Bool result = NS_FALSE0; | |||
1191 | ||||
1192 | NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0)); | |||
1193 | ||||
1194 | if (handlePtr->connected) { | |||
1195 | time_t minAccess, minOpen; | |||
1196 | ||||
1197 | minAccess = now - handlePtr->poolPtr->maxidle.sec; | |||
1198 | minOpen = now - handlePtr->poolPtr->maxopen.sec; | |||
1199 | if ((handlePtr->poolPtr->maxidle.sec > 0 && handlePtr->atime < minAccess) || | |||
1200 | (handlePtr->poolPtr->maxopen.sec > 0 && (handlePtr->otime < minOpen)) || | |||
1201 | (handlePtr->stale) || | |||
1202 | (handlePtr->poolPtr->stale_on_close > handlePtr->stale_on_close)) { | |||
1203 | ||||
1204 | Ns_Log(Notice, "nsdb: closing %s handle in pool '%s'", | |||
1205 | (handlePtr->poolPtr->maxidle.sec > 0 && handlePtr->atime < minAccess) ? "idle" | |||
1206 | : (handlePtr->poolPtr->maxopen.sec > 0 && (handlePtr->otime < minOpen) ? "old" | |||
1207 | : "stale"), | |||
1208 | handlePtr->poolname); | |||
1209 | ||||
1210 | result = NS_TRUE1; | |||
1211 | } | |||
1212 | } | |||
1213 | ||||
1214 | return result; | |||
1215 | } | |||
1216 | ||||
1217 | ||||
1218 | /* | |||
1219 | *---------------------------------------------------------------------- | |||
1220 | * | |||
1221 | * CheckArgProc -- | |||
1222 | * | |||
1223 | * Ns_ArgProc callback for the pool checker. | |||
1224 | * | |||
1225 | * Results: | |||
1226 | * None. | |||
1227 | * | |||
1228 | * Side effects: | |||
1229 | * Copies name of pool to given dstring. | |||
1230 | * | |||
1231 | *---------------------------------------------------------------------- | |||
1232 | */ | |||
1233 | ||||
1234 | static void | |||
1235 | CheckArgProc(Tcl_DString *dsPtr, const void *arg) | |||
1236 | { | |||
1237 | const Pool *poolPtr = arg; | |||
1238 | ||||
1239 | Tcl_DStringAppendElement(dsPtr, poolPtr->name); | |||
1240 | } | |||
1241 | ||||
1242 | ||||
1243 | /* | |||
1244 | *---------------------------------------------------------------------- | |||
1245 | * | |||
1246 | * TransferHandleStats -- | |||
1247 | * | |||
1248 | * Transfer the cached statistics values kept per handle into the | |||
1249 | * pool statistics (sqlTime and statementCount). The purpose of per | |||
1250 | * handle caching is to avoid frequent locking on the pool mutex. | |||
1251 | * | |||
1252 | * It is assumed that the pool data is mutex protected by the caller. | |||
1253 | * | |||
1254 | * Results: | |||
1255 | * None. | |||
1256 | * | |||
1257 | * Side effects: | |||
1258 | * Updates poolPtr->statementCount and poolPtr->sqlTime. | |||
1259 | * | |||
1260 | *---------------------------------------------------------------------- | |||
1261 | */ | |||
1262 | static void | |||
1263 | TransferHandleStats(Handle *handlePtr) | |||
1264 | { | |||
1265 | NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0)); | |||
1266 | ||||
1267 | if (handlePtr->statementCount > 0) { | |||
1268 | if (handlePtr->sqlTime.sec != 0 || handlePtr->sqlTime.usec != 0) { | |||
1269 | Ns_IncrTime(&handlePtr->poolPtr->sqlTime, handlePtr->sqlTime.sec, handlePtr->sqlTime.usec); | |||
1270 | handlePtr->sqlTime.sec = 0; | |||
1271 | handlePtr->sqlTime.usec = 0; | |||
1272 | } | |||
1273 | handlePtr->poolPtr->statementCount += handlePtr->statementCount; | |||
1274 | handlePtr->statementCount = 0; | |||
1275 | } | |||
1276 | } | |||
1277 | ||||
1278 | /* | |||
1279 | *---------------------------------------------------------------------- | |||
1280 | * | |||
1281 | * CheckPool -- | |||
1282 | * | |||
1283 | * Verify all handles in a pool are not stale. | |||
1284 | * | |||
1285 | * Results: | |||
1286 | * None. | |||
1287 | * | |||
1288 | * Side effects: | |||
1289 | * Stale handles, if any, are closed. | |||
1290 | * | |||
1291 | *---------------------------------------------------------------------- | |||
1292 | */ | |||
1293 | static void | |||
1294 | CheckPool(void *arg, int UNUSED(id)UNUSED_id __attribute__((__unused__))) | |||
1295 | { | |||
1296 | Pool *poolPtr = arg; | |||
1297 | Handle *handlePtr; | |||
1298 | ||||
1299 | /* | |||
1300 | * Grab the entire list of handles from the pool. | |||
1301 | */ | |||
1302 | Ns_MutexLock(&poolPtr->lock); | |||
1303 | handlePtr = poolPtr->firstPtr; | |||
1304 | poolPtr->firstPtr = poolPtr->lastPtr = NULL((void*)0); | |||
1305 | Ns_MutexUnlock(&poolPtr->lock); | |||
1306 | ||||
1307 | /* | |||
1308 | * Run through the list of handles, closing any | |||
1309 | * which have gone stale, and then return them | |||
1310 | * all to the pool. | |||
1311 | */ | |||
1312 | ||||
1313 | if (handlePtr != NULL((void*)0)) { | |||
1314 | Handle *checkedPtr = NULL((void*)0); | |||
1315 | time_t now; | |||
1316 | ||||
1317 | time(&now); | |||
1318 | ||||
1319 | while (handlePtr != NULL((void*)0)) { | |||
1320 | Handle *nextPtr = handlePtr->nextPtr; | |||
1321 | ||||
1322 | if (IsStale(handlePtr, now) == NS_TRUE1) { | |||
1323 | NsDbDisconnect((Ns_DbHandle *) handlePtr); | |||
1324 | } | |||
1325 | handlePtr->nextPtr = checkedPtr; | |||
1326 | checkedPtr = handlePtr; | |||
1327 | handlePtr = nextPtr; | |||
1328 | } | |||
1329 | ||||
1330 | Ns_MutexLock(&poolPtr->lock); | |||
1331 | handlePtr = checkedPtr; | |||
1332 | while (handlePtr != NULL((void*)0)) { | |||
1333 | Handle *nextPtr = handlePtr->nextPtr; | |||
1334 | ||||
1335 | TransferHandleStats(handlePtr); | |||
1336 | ReturnHandle(handlePtr); | |||
1337 | handlePtr = nextPtr; | |||
1338 | } | |||
1339 | if (poolPtr->waiting != 0) { | |||
1340 | Ns_CondSignal(&poolPtr->getCond); | |||
1341 | } | |||
1342 | Ns_MutexUnlock(&poolPtr->lock); | |||
1343 | } | |||
1344 | } | |||
1345 | ||||
1346 | ||||
1347 | /* | |||
1348 | *---------------------------------------------------------------------- | |||
1349 | * | |||
1350 | * CreatePool -- | |||
1351 | * | |||
1352 | * Create a new pool using the given driver. | |||
1353 | * | |||
1354 | * Results: | |||
1355 | * Pointer to newly allocated Pool structure. | |||
1356 | * | |||
1357 | * Side effects: | |||
1358 | * None. | |||
1359 | * | |||
1360 | *---------------------------------------------------------------------- | |||
1361 | */ | |||
1362 | ||||
1363 | static Pool * | |||
1364 | CreatePool(const char *pool, const char *path, const char *driver) | |||
1365 | { | |||
1366 | Pool *poolPtr; | |||
1367 | struct DbDriver *driverPtr; | |||
1368 | Ns_Time checkinterval; | |||
1369 | ||||
1370 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
1371 | NS_NONNULL_ASSERT(path != NULL)((void) (0)); | |||
1372 | ||||
1373 | if (driver == NULL((void*)0)) { | |||
1374 | Ns_Log(Error, "dbinit: no driver for pool '%s'", pool); | |||
1375 | driverPtr = NULL((void*)0); | |||
1376 | } else { | |||
1377 | driverPtr = NsDbLoadDriver(driver); | |||
1378 | } | |||
1379 | ||||
1380 | if (driverPtr == NULL((void*)0)) { | |||
1381 | poolPtr = NULL((void*)0); | |||
1382 | ||||
1383 | } else { | |||
1384 | int i; | |||
1385 | const char *source; | |||
1386 | ||||
1387 | /* | |||
1388 | * Load the configured values. | |||
1389 | */ | |||
1390 | source = Ns_ConfigGetValue(path, "datasource"); | |||
1391 | if (source == NULL((void*)0)) { | |||
1392 | Ns_Log(Error, "dbinit: missing datasource for pool '%s'", pool); | |||
1393 | return NULL((void*)0); | |||
1394 | } | |||
1395 | /* | |||
1396 | * Allocate Pool structure and initialize its members | |||
1397 | */ | |||
1398 | poolPtr = ns_calloc(1u, sizeof(Pool)); | |||
1399 | poolPtr->driver = driver; | |||
1400 | poolPtr->driverPtr = driverPtr; | |||
1401 | Ns_MutexInit(&poolPtr->lock); | |||
1402 | Ns_MutexSetName2(&poolPtr->lock, "nsdb", pool); | |||
1403 | Ns_CondInit(&poolPtr->waitCond); | |||
1404 | Ns_CondInit(&poolPtr->getCond); | |||
1405 | poolPtr->source = source; | |||
1406 | poolPtr->name = pool; | |||
1407 | poolPtr->user = Ns_ConfigGetValue(path, "user"); | |||
1408 | poolPtr->pass = Ns_ConfigGetValue(path, "password"); | |||
1409 | poolPtr->desc = Ns_ConfigGetValue("ns/db/pools", pool); | |||
1410 | poolPtr->stale_on_close = 0; | |||
1411 | poolPtr->fVerboseError = Ns_ConfigBool(path, "logsqlerrors", NS_FALSE0); | |||
1412 | poolPtr->nhandles = Ns_ConfigIntRange(path, "connections", 2, 0, INT_MAX2147483647); | |||
1413 | ||||
1414 | Ns_ConfigTimeUnitRange(path, "maxidle", | |||
1415 | "5m", 0, 0, INT_MAX2147483647, 0, &poolPtr->maxidle); | |||
1416 | Ns_ConfigTimeUnitRange(path, "maxopen", | |||
1417 | "60m", 0, 0, INT_MAX2147483647, 0, &poolPtr->maxopen); | |||
1418 | if (poolPtr->maxidle.usec != 0) { | |||
1419 | Ns_Log(Warning, "maxidle is implemented based on seconds granularity. " | |||
1420 | "Fractions of seconds are ignored"); | |||
1421 | } | |||
1422 | if (poolPtr->maxopen.usec != 0) { | |||
1423 | Ns_Log(Warning, "maxopen is implemented based on seconds granularity. " | |||
1424 | "Fractions of seconds are ignored"); | |||
1425 | } | |||
1426 | ||||
1427 | Ns_ConfigTimeUnitRange(path, "logminduration", | |||
1428 | "0ms", 0, 0, INT_MAX2147483647, 0, &poolPtr->minDuration); | |||
1429 | if (poolPtr->minDuration.sec != 0 || poolPtr->minDuration.usec != 0) { | |||
1430 | Ns_Log(Notice, "dbinit: set LogMinDuration for pool %s to " NS_TIME_FMT"%" "l" "d" ".%06ld", | |||
1431 | pool, (int64_t)poolPtr->minDuration.sec, | |||
1432 | poolPtr->minDuration.usec); | |||
1433 | } | |||
1434 | ||||
1435 | /* | |||
1436 | * Allocate the handles in the pool | |||
1437 | */ | |||
1438 | poolPtr->firstPtr = poolPtr->lastPtr = NULL((void*)0); | |||
1439 | for (i = 0; i < poolPtr->nhandles; ++i) { | |||
1440 | Handle *handlePtr = ns_malloc(sizeof(Handle)); | |||
1441 | ||||
1442 | Ns_DStringInitTcl_DStringInit(&handlePtr->dsExceptionMsg); | |||
1443 | handlePtr->poolPtr = poolPtr; | |||
1444 | handlePtr->connection = NULL((void*)0); | |||
1445 | handlePtr->connected = NS_FALSE0; | |||
1446 | handlePtr->fetchingRows = NS_FALSE0; | |||
1447 | handlePtr->row = Ns_SetCreate(NS_SET_NAME_DB"db"); | |||
1448 | #ifdef NS_SET_DEBUG | |||
1449 | Ns_Log(Notice, "Ns_DbInit CreatePool %s %i: %p", pool, i, (void*)handlePtr->row); | |||
1450 | #endif | |||
1451 | handlePtr->cExceptionCode[0] = '\0'; | |||
1452 | handlePtr->otime = handlePtr->atime = 0; | |||
1453 | handlePtr->stale = NS_FALSE0; | |||
1454 | handlePtr->stale_on_close = 0; | |||
1455 | handlePtr->statementCount = 0; | |||
1456 | handlePtr->sqlTime.sec = 0; | |||
1457 | handlePtr->sqlTime.usec = 0; | |||
1458 | ||||
1459 | /* | |||
1460 | * The following elements of the Handle structure could be | |||
1461 | * obtained by dereferencing the poolPtr. They're only needed | |||
1462 | * to maintain the original Ns_DbHandle structure definition | |||
1463 | * which was designed to allow handles outside of pools, a | |||
1464 | * feature no longer supported. | |||
1465 | */ | |||
1466 | ||||
1467 | handlePtr->driver = driver; | |||
1468 | handlePtr->datasource = poolPtr->source; | |||
1469 | handlePtr->user = poolPtr->user; | |||
1470 | handlePtr->password = poolPtr->pass; | |||
1471 | handlePtr->verbose = poolPtr->fVerboseError; | |||
1472 | handlePtr->poolname = pool; | |||
1473 | ReturnHandle(handlePtr); | |||
1474 | } | |||
1475 | ||||
1476 | Ns_ConfigTimeUnitRange(path, "checkinterval", | |||
1477 | "5m", 1, 0, INT_MAX2147483647, 0, &checkinterval); | |||
1478 | ||||
1479 | (void) Ns_ScheduleProcEx(CheckPool, poolPtr, 0, &checkinterval, NULL((void*)0)); | |||
1480 | } | |||
1481 | return poolPtr; | |||
1482 | } | |||
1483 | ||||
1484 | ||||
1485 | /* | |||
1486 | *---------------------------------------------------------------------- | |||
1487 | * | |||
1488 | * Connect -- | |||
1489 | * | |||
1490 | * Connect a handle by opening the database. | |||
1491 | * | |||
1492 | * Results: | |||
1493 | * NS_OK if connect ok, NS_ERROR otherwise. | |||
1494 | * | |||
1495 | * Side effects: | |||
1496 | * None. | |||
1497 | * | |||
1498 | *---------------------------------------------------------------------- | |||
1499 | */ | |||
1500 | ||||
1501 | static Ns_ReturnCode | |||
1502 | Connect(Handle *handlePtr) | |||
1503 | { | |||
1504 | Ns_ReturnCode status; | |||
1505 | ||||
1506 | NS_NONNULL_ASSERT(handlePtr != NULL)((void) (0)); | |||
1507 | ||||
1508 | status = NsDbOpen((Ns_DbHandle *) handlePtr); | |||
1509 | if (status != NS_OK) { | |||
1510 | handlePtr->connected = NS_FALSE0; | |||
1511 | handlePtr->atime = handlePtr->otime = 0; | |||
1512 | handlePtr->stale = NS_FALSE0; | |||
1513 | } else { | |||
1514 | static uintptr_t sessionId = 0u; | |||
1515 | ||||
1516 | Ns_MutexLock(&sessionMutex); | |||
1517 | sessionId++; | |||
1518 | Ns_MutexUnlock(&sessionMutex); | |||
1519 | ||||
1520 | handlePtr->connected = NS_TRUE1; | |||
1521 | handlePtr->atime = handlePtr->otime = time(NULL((void*)0)); | |||
1522 | handlePtr->sessionId = sessionId; | |||
1523 | } | |||
1524 | ||||
1525 | return status; | |||
1526 | } | |||
1527 | ||||
1528 | ||||
1529 | /* | |||
1530 | *---------------------------------------------------------------------- | |||
1531 | * | |||
1532 | * IncrCount -- | |||
1533 | * | |||
1534 | * Update per-thread count of allocated handles. If count == 0, | |||
1535 | * return the current number of allocated handles for this pool. | |||
1536 | * | |||
1537 | * Results: | |||
1538 | * Previous count of allocated handles. | |||
1539 | * | |||
1540 | * Side effects: | |||
1541 | * None. | |||
1542 | * | |||
1543 | *---------------------------------------------------------------------- | |||
1544 | */ | |||
1545 | ||||
1546 | static int | |||
1547 | IncrCount(const char *UNUSED(context)UNUSED_context __attribute__((__unused__)), const Pool *poolPtr, int incr) | |||
1548 | { | |||
1549 | Tcl_HashTable *tablePtr; | |||
1550 | Tcl_HashEntry *hPtr; | |||
1551 | int prev, count, isNew; | |||
1552 | ||||
1553 | /*NS_NONNULL_ASSERT(context != NULL);*/ | |||
1554 | NS_NONNULL_ASSERT(poolPtr != NULL)((void) (0)); | |||
1555 | ||||
1556 | tablePtr = Ns_TlsGet(&tls); | |||
1557 | if (tablePtr == NULL((void*)0)) { | |||
1558 | tablePtr = ns_malloc(sizeof(Tcl_HashTable)); | |||
1559 | Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS(1)); | |||
1560 | Ns_TlsSet(&tls, tablePtr); | |||
1561 | } | |||
1562 | hPtr = Tcl_CreateHashEntry(tablePtr, (const char *) poolPtr, &isNew)(*((tablePtr)->createProc))(tablePtr, (const char *)((const char *) poolPtr), &isNew); | |||
1563 | if (isNew != 0) { | |||
1564 | prev = 0; | |||
1565 | } else { | |||
1566 | prev = PTR2INT(Tcl_GetHashValue(hPtr))((int)(intptr_t)(((hPtr)->clientData))); | |||
1567 | } | |||
1568 | count = prev + incr; | |||
1569 | if (count
| |||
1570 | Tcl_DeleteHashEntry(hPtr); | |||
1571 | } else if (count
| |||
1572 | Tcl_SetHashValue(hPtr, INT2PTR(count))((hPtr)->clientData = (ClientData) (((void *)(intptr_t)(count )))); | |||
| ||||
1573 | } | |||
1574 | ||||
1575 | return prev; | |||
1576 | } | |||
1577 | ||||
1578 | ||||
1579 | ||||
1580 | /* | |||
1581 | *---------------------------------------------------------------------- | |||
1582 | * | |||
1583 | * GetServer -- | |||
1584 | * | |||
1585 | * Get per-server data. | |||
1586 | * | |||
1587 | * Results: | |||
1588 | * Pointer to per-server data. | |||
1589 | * | |||
1590 | * Side effects: | |||
1591 | * None. | |||
1592 | * | |||
1593 | *---------------------------------------------------------------------- | |||
1594 | */ | |||
1595 | ||||
1596 | static ServData * | |||
1597 | GetServer(const char *server) | |||
1598 | { | |||
1599 | ServData *result = NULL((void*)0); | |||
1600 | const Tcl_HashEntry *hPtr; | |||
1601 | ||||
1602 | NS_NONNULL_ASSERT(server != NULL)((void) (0)); | |||
1603 | ||||
1604 | hPtr = Tcl_FindHashEntry(&serversTable, server)(*((&serversTable)->findProc))(&serversTable, (const char *)(server)); | |||
1605 | if (hPtr != NULL((void*)0)) { | |||
1606 | result = Tcl_GetHashValue(hPtr)((hPtr)->clientData); | |||
1607 | } | |||
1608 | return result; | |||
1609 | } | |||
1610 | ||||
1611 | ||||
1612 | /* | |||
1613 | *---------------------------------------------------------------------- | |||
1614 | * | |||
1615 | * FreeTable -- | |||
1616 | * | |||
1617 | * Free the per-thread count of allocated handles table. | |||
1618 | * | |||
1619 | * Results: | |||
1620 | * None. | |||
1621 | * | |||
1622 | * Side effects: | |||
1623 | * None. | |||
1624 | * | |||
1625 | *---------------------------------------------------------------------- | |||
1626 | */ | |||
1627 | ||||
1628 | static void | |||
1629 | FreeTable(void *arg) | |||
1630 | { | |||
1631 | Tcl_HashTable *tablePtr = arg; | |||
1632 | ||||
1633 | Tcl_DeleteHashTable(tablePtr); | |||
1634 | ns_free(tablePtr); | |||
1635 | } | |||
1636 | ||||
1637 | ||||
1638 | /* | |||
1639 | *---------------------------------------------------------------------- | |||
1640 | * | |||
1641 | * NsDbGetSessionId -- | |||
1642 | * | |||
1643 | * Return the current sessionId | |||
1644 | * | |||
1645 | * Results: | |||
1646 | * sessionId | |||
1647 | * | |||
1648 | * Side effects: | |||
1649 | * None. | |||
1650 | * | |||
1651 | *---------------------------------------------------------------------- | |||
1652 | */ | |||
1653 | uintptr_t | |||
1654 | NsDbGetSessionId(const Ns_DbHandle *handle) | |||
1655 | { | |||
1656 | NS_NONNULL_ASSERT(handle != NULL)((void) (0)); | |||
1657 | ||||
1658 | return ((const Handle *)handle)->sessionId; | |||
1659 | } | |||
1660 | ||||
1661 | ||||
1662 | /* | |||
1663 | *---------------------------------------------------------------------- | |||
1664 | * | |||
1665 | * Ns_DbListMinDurations -- | |||
1666 | * | |||
1667 | * Introspection function to list min duration for every available | |||
1668 | * pool. | |||
1669 | * | |||
1670 | * Results: | |||
1671 | * Tcl_ListObj containing pairs of pool names and minDurations. | |||
1672 | * | |||
1673 | * Side effects: | |||
1674 | * None. | |||
1675 | * | |||
1676 | *---------------------------------------------------------------------- | |||
1677 | */ | |||
1678 | ||||
1679 | Tcl_Obj * | |||
1680 | Ns_DbListMinDurations(Tcl_Interp *interp, const char *server) | |||
1681 | { | |||
1682 | Tcl_Obj *resultObj; | |||
1683 | const char *pool; | |||
1684 | ||||
1685 | NS_NONNULL_ASSERT(interp != NULL)((void) (0)); | |||
1686 | NS_NONNULL_ASSERT(server != NULL)((void) (0)); | |||
1687 | ||||
1688 | resultObj = Tcl_NewListObj(0, NULL((void*)0)); | |||
1689 | pool = Ns_DbPoolList(server); | |||
1690 | if (pool != NULL((void*)0)) { | |||
1691 | for ( ; *pool != '\0'; pool += strlen(pool) + 1u) { | |||
1692 | char buffer[100]; | |||
1693 | const Pool *poolPtr; | |||
1694 | int len; | |||
1695 | ||||
1696 | poolPtr = GetPool(pool); | |||
1697 | (void) Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(pool, -1)); | |||
1698 | len = snprintf(buffer, sizeof(buffer), NS_TIME_FMT,__builtin___snprintf_chk (buffer, sizeof(buffer), 2 - 1, __builtin_object_size (buffer, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)poolPtr-> minDuration.sec, poolPtr->minDuration.usec) | |||
1699 | (int64_t)poolPtr->minDuration.sec, poolPtr->minDuration.usec)__builtin___snprintf_chk (buffer, sizeof(buffer), 2 - 1, __builtin_object_size (buffer, 2 > 1), "%" "l" "d" ".%06ld", (int64_t)poolPtr-> minDuration.sec, poolPtr->minDuration.usec); | |||
1700 | (void) Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(buffer, len)); | |||
1701 | } | |||
1702 | } | |||
1703 | return resultObj; | |||
1704 | } | |||
1705 | ||||
1706 | ||||
1707 | /* | |||
1708 | *---------------------------------------------------------------------- | |||
1709 | * | |||
1710 | * Ns_DbGetMinDuration -- | |||
1711 | * | |||
1712 | * Return the minDuration of the specified pool in the third | |||
1713 | * argument. | |||
1714 | * | |||
1715 | * Results: | |||
1716 | * Tcl result code | |||
1717 | * | |||
1718 | * Side effects: | |||
1719 | * None. | |||
1720 | * | |||
1721 | *---------------------------------------------------------------------- | |||
1722 | */ | |||
1723 | ||||
1724 | int | |||
1725 | Ns_DbGetMinDuration(Tcl_Interp *interp, const char *pool, Ns_Time **minDuration) | |||
1726 | { | |||
1727 | Pool *poolPtr; | |||
1728 | int result; | |||
1729 | ||||
1730 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
1731 | NS_NONNULL_ASSERT(minDuration != NULL)((void) (0)); | |||
1732 | ||||
1733 | /* | |||
1734 | * Get the poolPtr | |||
1735 | */ | |||
1736 | poolPtr = GetPool(pool); | |||
1737 | if (poolPtr == NULL((void*)0) && interp != NULL((void*)0)) { | |||
1738 | Ns_TclPrintfResult(interp, "Invalid pool '%s'", pool); | |||
1739 | result = TCL_ERROR1; | |||
1740 | } else { | |||
1741 | /* | |||
1742 | * Return the duration. | |||
1743 | */ | |||
1744 | *minDuration = &(poolPtr->minDuration); | |||
1745 | result = TCL_OK0; | |||
1746 | } | |||
1747 | return result; | |||
1748 | } | |||
1749 | ||||
1750 | ||||
1751 | /* | |||
1752 | *---------------------------------------------------------------------- | |||
1753 | * | |||
1754 | * Ns_DbSetMinDuration -- | |||
1755 | * | |||
1756 | * Set the minDuration of the specified pool | |||
1757 | * | |||
1758 | * Results: | |||
1759 | * Tcl result code | |||
1760 | * | |||
1761 | * Side effects: | |||
1762 | * None. | |||
1763 | * | |||
1764 | *---------------------------------------------------------------------- | |||
1765 | */ | |||
1766 | ||||
1767 | int | |||
1768 | Ns_DbSetMinDuration(Tcl_Interp *interp, const char *pool, const Ns_Time *minDuration) | |||
1769 | { | |||
1770 | Pool *poolPtr; | |||
1771 | int result; | |||
1772 | ||||
1773 | NS_NONNULL_ASSERT(interp != NULL)((void) (0)); | |||
1774 | NS_NONNULL_ASSERT(pool != NULL)((void) (0)); | |||
1775 | NS_NONNULL_ASSERT(minDuration != NULL)((void) (0)); | |||
1776 | ||||
1777 | /* | |||
1778 | * Get the poolPtr | |||
1779 | */ | |||
1780 | poolPtr = GetPool(pool); | |||
1781 | if (poolPtr == NULL((void*)0)) { | |||
1782 | Ns_TclPrintfResult(interp, "Invalid pool '%s'", pool); | |||
1783 | result = TCL_ERROR1; | |||
1784 | } else { | |||
1785 | /* | |||
1786 | * Set the duration. | |||
1787 | */ | |||
1788 | poolPtr->minDuration = *minDuration; | |||
1789 | result = TCL_OK0; | |||
1790 | } | |||
1791 | return result; | |||
1792 | } | |||
1793 | ||||
1794 | /* | |||
1795 | * Local Variables: | |||
1796 | * mode: c | |||
1797 | * c-basic-offset: 4 | |||
1798 | * fill-column: 72 | |||
1799 | * indent-tabs-mode: nil | |||
1800 | * End: | |||
1801 | */ |