1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * author M.L. Kersten, P. Boncz, N.Nes
11 * System state information
12 * This document introduces a series of bats and operations that provide access
13 * to information stored within the Monet Version 5 internal data structures.
14 * In all cases, pseudo BAT operation returns a transient BAT that
15 * should be garbage collected after being used.
16 *
17 * The main performance drain would be to use a pseudo BAT directly to
18 * successively access it components. This can be avoided by first assigning
19 * the pseudo BAT to a variable.
20 */
21
22#include "monetdb_config.h"
23#include "gdk.h"
24#include <time.h>
25#include "mal_exception.h"
26#include "status.h"
27#ifdef HAVE_UNISTD_H
28# include <unistd.h>
29#endif
30
31#ifdef HAVE_SYS_TIMES_H
32# include <sys/times.h>
33#endif
34
35#ifdef HAVE_SYS_RESOURCE_H
36# include <sys/resource.h>
37#endif
38
39static int
40pseudo(bat *ret, bat *ret2, BAT *bn, BAT *b) {
41 *ret = bn->batCacheid;
42 BBPkeepref(*ret);
43 *ret2 = b->batCacheid;
44 BBPkeepref(*ret2);
45 return 0;
46}
47
48str
49SYSgetmem_cursize(lng *num)
50{
51 *num = GDKmem_cursize();
52 return MAL_SUCCEED;
53}
54
55str
56SYSgetmem_maxsize(lng *num)
57{
58 *num = GDK_mem_maxsize;
59 return MAL_SUCCEED;
60}
61
62str
63SYSsetmem_maxsize(void *ret, const lng *num)
64{
65 size_t sze = 0;
66 (void) ret;
67 if (*num < 0)
68 throw(ILLARG, "status.mem_maxsize", "new size must not be < 0");
69#if SIZEOF_SIZE_T == SIZEOF_INT
70 {
71 lng size_t_max = 2 * (lng)INT_MAX;
72 if (*num > size_t_max)
73 throw(ILLARG, "status.mem_maxsize", "new size must not be > " LLFMT, size_t_max);
74 }
75#endif
76 GDK_mem_maxsize = sze;
77 return MAL_SUCCEED;
78}
79
80str
81SYSgetvm_cursize(lng *num)
82{
83 *num = GDKvm_cursize();
84 return MAL_SUCCEED;
85}
86
87str
88SYSgetvm_maxsize(lng *num)
89{
90 *num = GDK_vm_maxsize;
91 return MAL_SUCCEED;
92}
93
94str
95SYSsetvm_maxsize(void *ret, const lng *num)
96{
97 (void) ret;
98 GDK_vm_maxsize = (size_t) *num;
99 return MAL_SUCCEED;
100}
101
102/*
103 * Performance
104 * To obtain a good impression of the Monet performance we need timing information.
105 * The most detailed information is best obtained with the system profiler.
106 *
107 * However, the direct approach is to enable the user to read the timers maintained
108 * internally. This is done with the CPU, IO, MEMORY, and BBP command which
109 * displays the elapsed time in seconds, user- and system-cpu time in milliseconds
110 * since its last invocation and the amount of space in use. The process
111 * identifier is used to differentiate among the possible processes.
112 *
113 * Note that in multi threaded mode the routine prints the elapsed
114 * time since the beginning of each process.
115 */
116#ifdef HAVE_TIMES
117static time_t clk = 0;
118static struct tms state;
119#endif
120
121str
122SYScpuStatistics(bat *ret, bat *ret2)
123{
124 lng i;
125 BAT *b, *bn;
126#ifdef HAVE_TIMES
127 struct tms newst;
128# ifndef HZ
129 static int HZ = 0;
130
131 if (HZ == 0) {
132# if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
133 HZ = sysconf(_SC_CLK_TCK);
134# else
135 HZ = CLK_TCK;
136# endif
137 }
138# endif
139#endif
140
141 bn = COLnew(0, TYPE_str, 32, TRANSIENT);
142 b = COLnew(0, TYPE_lng, 32, TRANSIENT);
143 if (b == 0 || bn == 0){
144 if ( b) BBPunfix(b->batCacheid);
145 if ( bn) BBPunfix(bn->batCacheid);
146 throw(MAL, "status.cpuStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
147 }
148#ifdef HAVE_TIMES
149 if (clk == 0) {
150 clk = time(0);
151 times(&state);
152 }
153 times(&newst);
154 /* store counters, ignore errors */
155 i = (lng) (time(0) - clk);
156 if (BUNappend(bn, "elapsed", false) != GDK_SUCCEED ||
157 BUNappend(b, &i, false) != GDK_SUCCEED)
158 goto bailout;
159 i = newst.tms_utime * 1000 / HZ;
160 if (BUNappend(bn, "user", false) != GDK_SUCCEED ||
161 BUNappend(b, &i, false) != GDK_SUCCEED)
162 goto bailout;
163 i = (newst.tms_utime - state.tms_utime) * 1000 / HZ;
164 if (BUNappend(bn, "elapuser", false) != GDK_SUCCEED ||
165 BUNappend(b, &i, false) != GDK_SUCCEED)
166 goto bailout;
167 i = newst.tms_stime * 1000 / HZ;
168 if (BUNappend(bn, "system", false) != GDK_SUCCEED ||
169 BUNappend(b, &i, false) != GDK_SUCCEED)
170 goto bailout;
171 i = (newst.tms_stime - state.tms_stime) * 1000 / HZ;
172 if (BUNappend(bn, "elapsystem", false) != GDK_SUCCEED ||
173 BUNappend(b, &i, false) != GDK_SUCCEED)
174 goto bailout;
175
176 state = newst;
177#else
178 i = lng_nil;
179 if (BUNappend(bn, "elapsed", false) != GDK_SUCCEED ||
180 BUNappend(b, &i, false) != GDK_SUCCEED ||
181 BUNappend(bn, "user", false) != GDK_SUCCEED ||
182 BUNappend(b, &i, false) != GDK_SUCCEED ||
183 BUNappend(bn, "elapuser", false) != GDK_SUCCEED ||
184 BUNappend(b, &i, false) != GDK_SUCCEED ||
185 BUNappend(bn, "system", false) != GDK_SUCCEED ||
186 BUNappend(b, &i, false) != GDK_SUCCEED ||
187 BUNappend(bn, "elapsystem", false) != GDK_SUCCEED ||
188 BUNappend(b, &i, false) != GDK_SUCCEED)
189 goto bailout;
190#endif
191 if (pseudo(ret,ret2,bn,b))
192 goto bailout;
193 return MAL_SUCCEED;
194 bailout:
195 BBPunfix(b->batCacheid);
196 BBPunfix(bn->batCacheid);
197 throw(MAL, "status.cpuStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
198}
199
200static size_t memincr;
201str
202SYSmemStatistics(bat *ret, bat *ret2)
203{
204 BAT *b, *bn;
205 lng i;
206
207 bn = COLnew(0,TYPE_str, 32, TRANSIENT);
208 b = COLnew(0, TYPE_lng, 32, TRANSIENT);
209 if (b == 0 || bn == 0) {
210 if ( b) BBPunfix(b->batCacheid);
211 if ( bn) BBPunfix(bn->batCacheid);
212 throw(MAL, "status.memStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
213 }
214
215 /* store counters, ignore errors */
216 i = (lng) (GDKmem_cursize() - memincr);
217 memincr = GDKmem_cursize();
218 if (BUNappend(bn, "memincr", false) != GDK_SUCCEED ||
219 BUNappend(b, &i, false) != GDK_SUCCEED)
220 goto bailout;
221 if (pseudo(ret,ret2,bn,b))
222 goto bailout;
223 return MAL_SUCCEED;
224 bailout:
225 BBPunfix(b->batCacheid);
226 BBPunfix(bn->batCacheid);
227 throw(MAL, "status.memStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
228}
229
230#define heap(X1,X2,X3,X4) \
231 if (X1) { \
232 sz = HEAPmemsize(X2); \
233 if (sz > *minsize) { \
234 sprintf(buf, X4"/%s", s); \
235 if (BUNappend(bn, buf, false) != GDK_SUCCEED || \
236 BUNappend(b, &sz, false) != GDK_SUCCEED) \
237 goto bailout; \
238 } \
239 X3 += sz; tot += sz; \
240 }
241#define heapvm(X1,X2,X3,X4) \
242 if (X1) { \
243 sz = HEAPvmsize(X2); \
244 if (sz > *minsize) { \
245 sprintf(buf, X4"/%s", s); \
246 if (BUNappend(bn, buf, false) != GDK_SUCCEED || \
247 BUNappend(b, &sz, false) != GDK_SUCCEED) \
248 goto bailout; \
249 } \
250 X3 += sz; tot += sz; \
251 }
252
253str
254SYSmem_usage(bat *ret, bat *ret2, const lng *minsize)
255{
256 lng hbuns = 0, tbuns = 0, hhsh = 0, thsh = 0, hind = 0, tind = 0, head = 0, tail = 0, tot = 0, n = 0, sz;
257 BAT *bn = COLnew(0, TYPE_str, 2 * getBBPsize(), TRANSIENT);
258 BAT *b = COLnew(0, TYPE_lng, 2 * getBBPsize(), TRANSIENT);
259 char buf[1024];
260 bat i;
261
262 if (b == 0 || bn == 0) {
263 if ( b) BBPunfix(b->batCacheid);
264 if ( bn) BBPunfix(bn->batCacheid);
265 throw(MAL, "status.memUsage", SQLSTATE(HY001) MAL_MALLOC_FAIL);
266 }
267 BBPlock();
268 for (i = 1; i < getBBPsize(); i++) {
269 BAT *c = BBPquickdesc(i, false);
270 str s;
271
272 if( c == NULL || !BBPvalid(i))
273 continue;
274
275 s = BBPname(i);
276 sz = 0;
277 if (BBP_desc(i))
278 sz += sizeof(BAT);
279 if (BBP_logical(i))
280 n += strLen(BBP_logical(i));
281 if (BBP_physical(i))
282 n += strLen(BBP_physical(i));
283
284 if (sz > *minsize) {
285 sprintf(buf, "desc/%s", s);
286 if (BUNappend(bn, buf, false) != GDK_SUCCEED ||
287 BUNappend(b, &sz, false) != GDK_SUCCEED)
288 goto bailout;
289 }
290 tot += (lng) sz;
291
292 if (c == NULL || isVIEW(c)) {
293 continue;
294 }
295 heap(1,&c->theap,tbuns,"tbuns");
296 heap(c->thash && c->thash != (Hash *) 1,&c->thash->heap,thsh,"thsh");
297 heap(c->tvheap,c->tvheap,tail,"tail");
298 }
299 /* totals per category */
300 if (BUNappend(bn, "_tot/hbuns", false) != GDK_SUCCEED ||
301 BUNappend(b, &hbuns, false) != GDK_SUCCEED ||
302 BUNappend(bn, "_tot/tbuns", false) != GDK_SUCCEED ||
303 BUNappend(b, &tbuns, false) != GDK_SUCCEED ||
304 BUNappend(bn, "_tot/head", false) != GDK_SUCCEED ||
305 BUNappend(b, &head, false) != GDK_SUCCEED ||
306 BUNappend(bn, "_tot/tail", false) != GDK_SUCCEED ||
307 BUNappend(b, &tail, false) != GDK_SUCCEED ||
308 BUNappend(bn, "_tot/hhsh", false) != GDK_SUCCEED ||
309 BUNappend(b, &hhsh, false) != GDK_SUCCEED ||
310 BUNappend(bn, "_tot/thsh", false) != GDK_SUCCEED ||
311 BUNappend(b, &thsh, false) != GDK_SUCCEED ||
312 BUNappend(bn, "_tot/hind", false) != GDK_SUCCEED ||
313 BUNappend(b, &hind, false) != GDK_SUCCEED ||
314 BUNappend(bn, "_tot/tind", false) != GDK_SUCCEED ||
315 BUNappend(b, &tind, false) != GDK_SUCCEED)
316 goto bailout;
317
318 /* special area 1: BBP rec */
319 sz = BBPlimit * sizeof(BBPrec) + n;
320 if (BUNappend(bn, "_tot/bbp", false) != GDK_SUCCEED ||
321 BUNappend(b, &sz, false) != GDK_SUCCEED)
322 goto bailout;
323 tot += sz;
324
325 /* this concludes all major traceable Monet memory usages */
326 tot += sz;
327 if (BUNappend(bn, "_tot/found", false) != GDK_SUCCEED ||
328 BUNappend(b, &tot, false) != GDK_SUCCEED)
329 goto bailout;
330
331 /* now look at what the global statistics report (to see if it coincides) */
332
333 /* measure actual heap size, includes wasted fragmented space and anon mmap space used by malloc() */
334 sz = GDKmem_cursize();
335 if (BUNappend(bn, "_tot/heap", false) != GDK_SUCCEED ||
336 BUNappend(b, &sz, false) != GDK_SUCCEED)
337 goto bailout;
338
339 tot = GDKmem_cursize();
340
341 /* allocated swap area memory that is not plain malloc() */
342 sz = MAX(0, sz - tot);
343 if (BUNappend(bn, "_tot/valloc", false) != GDK_SUCCEED ||
344 BUNappend(b, &sz, false) != GDK_SUCCEED)
345 goto bailout;
346
347 /* swap-area memory is in either GDKvmalloc or heap */
348 if (BUNappend(bn, "_tot/swapmem", false) != GDK_SUCCEED ||
349 BUNappend(b, &tot, false) != GDK_SUCCEED)
350 goto bailout;
351
352 BBPunlock();
353 *ret = bn->batCacheid;
354 BBPkeepref(bn->batCacheid);
355 *ret2 = b->batCacheid;
356 BBPkeepref(b->batCacheid);
357
358 return MAL_SUCCEED;
359
360 bailout:
361 BBPunlock();
362 BBPunfix(b->batCacheid);
363 BBPunfix(bn->batCacheid);
364 throw(MAL, "status.memUsage", SQLSTATE(HY001) MAL_MALLOC_FAIL);
365}
366
367str
368SYSvm_usage(bat *ret, bat *ret2, const lng *minsize)
369{
370 lng hbuns = 0, tbuns = 0, hhsh = 0, thsh = 0, hind = 0, tind = 0, head = 0, tail = 0, tot = 0, sz;
371 BAT *bn = COLnew(0, TYPE_str, 2 * getBBPsize(), TRANSIENT);
372 BAT *b = COLnew(0, TYPE_lng, 2 * getBBPsize(), TRANSIENT);
373 char buf[1024];
374 bat i;
375
376 if (b == 0 || bn == 0) {
377 if ( b) BBPunfix(b->batCacheid);
378 if ( bn) BBPunfix(bn->batCacheid);
379 throw(MAL, "status.vmStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
380 }
381 BBPlock();
382 for (i = 1; i < getBBPsize(); i++) {
383 BAT *c;
384 str s;
385
386 if (!BBPvalid(i))
387 continue;
388
389 s = BBPname(i);
390 c = BBP_cache(i);
391 if (c == NULL || isVIEW(c)) {
392 continue;
393 }
394 heapvm(1,&c->theap,tbuns,"tcuns");
395 heapvm(c->thash && c->thash != (Hash *) 1,&c->thash->heap,thsh,"thsh");
396 heapvm(c->tvheap,c->tvheap,tail,"tail");
397 }
398 /* totals per category */
399 if (BUNappend(bn, "_tot/hbuns", false) != GDK_SUCCEED ||
400 BUNappend(b, &hbuns, false) != GDK_SUCCEED ||
401 BUNappend(bn, "_tot/tbuns", false) != GDK_SUCCEED ||
402 BUNappend(b, &tbuns, false) != GDK_SUCCEED ||
403 BUNappend(bn, "_tot/head", false) != GDK_SUCCEED ||
404 BUNappend(b, &head, false) != GDK_SUCCEED ||
405 BUNappend(bn, "_tot/tail", false) != GDK_SUCCEED ||
406 BUNappend(b, &tail, false) != GDK_SUCCEED ||
407 BUNappend(bn, "_tot/hhsh", false) != GDK_SUCCEED ||
408 BUNappend(b, &hhsh, false) != GDK_SUCCEED ||
409 BUNappend(bn, "_tot/thsh", false) != GDK_SUCCEED ||
410 BUNappend(b, &thsh, false) != GDK_SUCCEED ||
411 BUNappend(bn, "_tot/hind", false) != GDK_SUCCEED ||
412 BUNappend(b, &hind, false) != GDK_SUCCEED ||
413 BUNappend(bn, "_tot/tind", false) != GDK_SUCCEED ||
414 BUNappend(b, &tind, false) != GDK_SUCCEED)
415 goto bailout;
416
417 /* special area 1: BBP rec */
418 sz = BBPlimit * sizeof(BBPrec);
419 if (BUNappend(bn, "_tot/bbp", false) != GDK_SUCCEED ||
420 BUNappend(b, &sz, false) != GDK_SUCCEED)
421 goto bailout;
422 tot += sz;
423
424
425 /* this concludes all major traceable Monet virtual memory usages */
426 tot += sz;
427 if (BUNappend(bn, "_tot/found", false) != GDK_SUCCEED ||
428 BUNappend(b, &tot, false) != GDK_SUCCEED)
429 goto bailout;
430
431 /* all VM is either GDKmmap or GDKvmalloc (possibly redirected GDKmalloc), *plus* the heap */
432 sz = GDKvm_cursize();
433 if (BUNappend(bn, "_tot/vm", false) != GDK_SUCCEED ||
434 BUNappend(b, &sz, false) != GDK_SUCCEED)
435 goto bailout;
436
437 BBPunlock();
438 *ret = bn->batCacheid;
439 BBPkeepref(bn->batCacheid);
440 *ret2 = b->batCacheid;
441 BBPkeepref(b->batCacheid);
442 return MAL_SUCCEED;
443
444 bailout:
445 BBPunlock();
446 BBPunfix(b->batCacheid);
447 BBPunfix(bn->batCacheid);
448 throw(MAL, "status.vmStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
449}
450
451/*
452 * Additional information on the process utilization is given by
453 * the ioStatistics command. The following information is obtained.
454 *
455 * @T
456 * \begin{tabular}{| l| l|}\hline
457 * maxrss &the maximum resident set size utilized (in kilobytes).\\
458 * minflt &the number of page faults serviced without any I/O\\
459 * &activity; here I/O activity is avoided by "reclaiming" a\\
460 *
461 * &activity; here I/O activity is avoided by "reclaiming" a\\
462 * &page frame from the list of pages awaiting reallocation.\\
463 * majflt &the number of page faults serviced that required I/O\\
464 * &activity.\\
465 * nswap &the number of times a process was "swapped" out of main\\
466 * &memory\\
467 * inblock &the number of times the file system had to perform input.\\
468 * oublock &the number of times the file system had to perform output.\\
469 * nvcsw &the number of times a context switch resulted due to a\\
470 * &process voluntarily giving up the processor before its\\
471 * &time slice was completed (usually to await availability of\\
472 * &a resource).\\
473 * nivcsw &the number of times a context switch resulted due to a\\
474 * &higher priority process becoming runnable or because the\\
475 * &current process exceeded its time slice.\\
476 * \end{tabular}
477 *
478 * The resource statistics are collected in a BAT. It can then
479 * be queried. A default listing is produced by the command usagecmd.
480 * (which should be moved to Monet)
481 *
482 * The BAT grows. It should be compacted.
483 */
484str
485SYSioStatistics(bat *ret, bat *ret2)
486{
487#ifdef HAVE_SYS_RESOURCE_H
488 struct rusage ru;
489#endif
490 lng i;
491 BAT *b, *bn;
492
493#ifdef HAVE_SYS_RESOURCE_H
494 getrusage(RUSAGE_SELF, &ru);
495#endif
496 bn = COLnew(0, TYPE_str, 32, TRANSIENT);
497 b = COLnew(0, TYPE_lng, 32, TRANSIENT);
498 if (b == 0 || bn == 0) {
499 if ( b) BBPunfix(b->batCacheid);
500 if ( bn) BBPunfix(bn->batCacheid);
501 throw(MAL, "status.ioStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
502 }
503
504#ifdef HAVE_SYS_RESOURCE_H
505 /* store counters, ignore errors */
506 i = ru.ru_maxrss;
507 if (BUNappend(bn, "maxrss", false) != GDK_SUCCEED ||
508 BUNappend(b, &i, false) != GDK_SUCCEED)
509 goto bailout;
510 i = ru.ru_minflt;
511 if (BUNappend(bn, "minflt", false) != GDK_SUCCEED ||
512 BUNappend(b, &i, false) != GDK_SUCCEED)
513 goto bailout;
514 i = ru.ru_majflt;
515 if (BUNappend(bn, "majflt", false) != GDK_SUCCEED ||
516 BUNappend(b, &i, false) != GDK_SUCCEED)
517 goto bailout;
518 i = ru.ru_nswap;
519 if (BUNappend(bn, "nswap", false) != GDK_SUCCEED ||
520 BUNappend(b, &i, false) != GDK_SUCCEED)
521 goto bailout;
522 i = ru.ru_inblock;
523 if (BUNappend(bn, "inblock", false) != GDK_SUCCEED ||
524 BUNappend(b, &i, false) != GDK_SUCCEED)
525 goto bailout;
526 i = ru.ru_oublock;
527 if (BUNappend(bn, "oublock", false) != GDK_SUCCEED ||
528 BUNappend(b, &i, false) != GDK_SUCCEED)
529 goto bailout;
530 i = ru.ru_nvcsw;
531 if (BUNappend(bn, "nvcsw", false) != GDK_SUCCEED ||
532 BUNappend(b, &i, false) != GDK_SUCCEED)
533 goto bailout;
534 i = ru.ru_nivcsw;
535 if (BUNappend(bn, "ninvcsw", false) != GDK_SUCCEED ||
536 BUNappend(b, &i, false) != GDK_SUCCEED)
537 goto bailout;
538#else
539 i = lng_nil;
540 if (BUNappend(bn, "maxrss", false) != GDK_SUCCEED ||
541 BUNappend(b, &i, false) != GDK_SUCCEED ||
542 BUNappend(bn, "minflt", false) != GDK_SUCCEED ||
543 BUNappend(b, &i, false) != GDK_SUCCEED ||
544 BUNappend(bn, "majflt", false) != GDK_SUCCEED ||
545 BUNappend(b, &i, false) != GDK_SUCCEED ||
546 BUNappend(bn, "nswap", false) != GDK_SUCCEED ||
547 BUNappend(b, &i, false) != GDK_SUCCEED ||
548 BUNappend(bn, "inblock", false) != GDK_SUCCEED ||
549 BUNappend(b, &i, false) != GDK_SUCCEED ||
550 BUNappend(bn, "oublock", false) != GDK_SUCCEED ||
551 BUNappend(b, &i, false) != GDK_SUCCEED ||
552 BUNappend(bn, "nvcsw", false) != GDK_SUCCEED ||
553 BUNappend(b, &i, false) != GDK_SUCCEED ||
554 BUNappend(bn, "ninvcsw", false) != GDK_SUCCEED ||
555 BUNappend(b, &i, false) != GDK_SUCCEED)
556 goto bailout;
557#endif
558
559 if (pseudo(ret,ret2,bn,b))
560 goto bailout;
561 return MAL_SUCCEED;
562
563 bailout:
564 BBPunfix(b->batCacheid);
565 BBPunfix(bn->batCacheid);
566 throw(MAL, "status.ioStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
567}
568
569str
570SYSgdkEnv(bat *ret, bat *ret2)
571{
572 int pbat = 0;
573 int pdisk = 0;
574 bat i;
575 int tmp = 0, per = 0;
576 BAT *b,*bn;
577
578 bn = COLnew(0, TYPE_str, 32, TRANSIENT);
579 b = COLnew(0, TYPE_int, 32, TRANSIENT);
580 if (b == 0 || bn == 0) {
581 if ( b) BBPunfix(b->batCacheid);
582 if ( bn) BBPunfix(bn->batCacheid);
583 throw(MAL, "status.batStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
584 }
585
586 for (i = 1; i < getBBPsize(); i++) {
587 if (BBPvalid(i)) {
588 pbat++;
589 if (BBP_cache(i)) {
590 if (BBP_cache(i)->batTransient)
591 tmp++;
592 else
593 per++;
594 } else {
595 pdisk++;
596 }
597 }
598 }
599 if (BUNappend(bn, "bats", false) != GDK_SUCCEED ||
600 BUNappend(b, &pbat, false) != GDK_SUCCEED ||
601 BUNappend(bn, "tmpbats", false) != GDK_SUCCEED ||
602 BUNappend(b, &tmp, false) != GDK_SUCCEED ||
603 BUNappend(bn, "perbats", false) != GDK_SUCCEED ||
604 BUNappend(b, &per, false) != GDK_SUCCEED ||
605 BUNappend(bn, "ondisk", false) != GDK_SUCCEED ||
606 BUNappend(b, &pdisk, false) != GDK_SUCCEED ||
607 pseudo(ret,ret2, bn,b)) {
608 BBPunfix(b->batCacheid);
609 BBPunfix(bn->batCacheid);
610 throw(MAL, "status.batStatistics", SQLSTATE(HY001) MAL_MALLOC_FAIL);
611 }
612 return MAL_SUCCEED;
613}
614
615str
616SYSgdkThread(bat *ret, bat *ret2)
617{
618 BAT *b, *bn;
619 int i;
620 Thread thr;
621
622 bn = COLnew(0,TYPE_int, THREADS, TRANSIENT);
623 b = COLnew(0, TYPE_str, THREADS, TRANSIENT);
624 if (b == 0 || bn == 0) {
625 if ( b) BBPunfix(b->batCacheid);
626 if ( bn) BBPunfix(bn->batCacheid);
627 throw(MAL, "status.getThreads", SQLSTATE(HY001) MAL_MALLOC_FAIL);
628 }
629
630 for (i = 1; i <= THREADS; i++) {
631 thr = THRget(i);
632 if (ATOMIC_GET(&thr->pid)){
633 if (BUNappend(bn, &thr->tid, false) != GDK_SUCCEED ||
634 BUNappend(b, thr->name? thr->name:"", false) != GDK_SUCCEED)
635 goto bailout;
636 }
637 }
638 if (pseudo(ret,ret2,bn,b))
639 goto bailout;
640 return MAL_SUCCEED;
641
642 bailout:
643 BBPunfix(b->batCacheid);
644 BBPunfix(bn->batCacheid);
645 throw(MAL, "status.getThreads", SQLSTATE(HY001) MAL_MALLOC_FAIL);
646}
647