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 | * (c) M.L.Kersten, P. Boncz |
11 | * BAT Buffer Pool |
12 | * It is primarilly meant to ease inspection of the BAT collection managed |
13 | * by the server. |
14 | */ |
15 | #include "monetdb_config.h" |
16 | #include "bbp.h" |
17 | |
18 | static int |
19 | pseudo(bat *ret, BAT *b, str X1,str X2) { |
20 | char buf[BUFSIZ]; |
21 | snprintf(buf,BUFSIZ,"%s_%s" , X1,X2); |
22 | if ((BBPindex(buf) <= 0 && BBPrename(b->batCacheid, buf) != 0) || BATroles(b,X2) != GDK_SUCCEED) { |
23 | BBPunfix(b->batCacheid); |
24 | return -1; |
25 | } |
26 | *ret = b->batCacheid; |
27 | BBPkeepref(*ret); |
28 | return -0; |
29 | } |
30 | |
31 | str |
32 | CMDbbpbind(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
33 | { |
34 | str name; |
35 | ValPtr lhs; |
36 | bat i; |
37 | int tt; |
38 | BAT *b; |
39 | |
40 | (void) cntxt; |
41 | (void) mb; /* fool compiler */ |
42 | lhs = &stk->stk[pci->argv[0]]; |
43 | name = *getArgReference_str(stk, pci, 1); |
44 | if (name == NULL || isIdentifier(name) < 0) |
45 | throw(MAL, "bbp.bind" , IDENTIFIER_EXPECTED); |
46 | i = BBPindex(name); |
47 | if (i == 0) |
48 | throw(MAL, "bbp.bind" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
49 | /* make sure you load the descriptors and heaps */ |
50 | b = (BAT *) BATdescriptor(i); |
51 | if (b == 0) |
52 | /* Simple ignore the binding if you can't find the bat */ |
53 | throw(MAL, "bbp.bind" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
54 | |
55 | /* check conformity of the actual type and the one requested */ |
56 | tt= getBatType(getArgType(mb,pci,0)); |
57 | if( b->ttype == TYPE_void && tt== TYPE_oid) tt= TYPE_void; |
58 | |
59 | if( tt != b->ttype){ |
60 | BBPunfix(i); |
61 | throw(MAL, "bbp.bind" , SEMANTIC_TYPE_MISMATCH ); |
62 | } |
63 | /* make sure we are not dealing with an about to be deleted bat */ |
64 | if( BBP_refs(b->batCacheid) == 1 && |
65 | BBP_lrefs(b->batCacheid) == 0){ |
66 | BBPunfix(i); |
67 | throw(MAL, "bbp.bind" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
68 | } |
69 | |
70 | BBPkeepref(b->batCacheid); |
71 | lhs->vtype = TYPE_bat; |
72 | lhs->val.bval = i; |
73 | return MAL_SUCCEED; |
74 | } |
75 | /* |
76 | * BBP status |
77 | * The BAT buffer pool datastructures describe the memory resident information |
78 | * on the whereabouts of the BATs. The three predominant tables are made accessible |
79 | * for inspection. |
80 | * |
81 | * The most interesting system bat for end-users is the BID-> NAME mapping, |
82 | * because it provides access to the system guaranteed persistent BAT identifier. |
83 | * It may be the case that the user already introduced a BAT with this name, |
84 | * it is simply removed first |
85 | */ |
86 | |
87 | str |
88 | CMDbbpNames(bat *ret) |
89 | { |
90 | BAT *b; |
91 | int i; |
92 | |
93 | b = COLnew(0, TYPE_str, getBBPsize(), TRANSIENT); |
94 | if (b == 0) |
95 | throw(MAL, "catalog.bbpNames" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
96 | |
97 | BBPlock(); |
98 | for (i = 1; i < getBBPsize(); i++) |
99 | if (i != b->batCacheid) { |
100 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i)) ) { |
101 | if (BUNappend(b, BBP_logical(i), false) != GDK_SUCCEED) { |
102 | BBPunlock(); |
103 | BBPreclaim(b); |
104 | throw(MAL, "catalog.bbpNames" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
105 | } |
106 | } |
107 | } |
108 | BBPunlock(); |
109 | if (pseudo(ret,b,"bbp" ,"name" )) |
110 | throw(MAL, "catalog.bbpNames" , GDK_EXCEPTION); |
111 | return MAL_SUCCEED; |
112 | } |
113 | str |
114 | CMDbbpDiskSpace(lng *ret) |
115 | { |
116 | *ret= getDiskSpace(); |
117 | return MAL_SUCCEED; |
118 | } |
119 | str |
120 | CMDgetPageSize(int *ret) |
121 | { |
122 | *ret= (int) MT_pagesize(); |
123 | return MAL_SUCCEED; |
124 | } |
125 | |
126 | str |
127 | CMDbbpName(str *ret, bat *bid) |
128 | { |
129 | *ret = (str) GDKstrdup(BBP_logical(*bid)); |
130 | if (*ret == NULL) |
131 | throw(MAL, "catalog.bbpName" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
132 | return MAL_SUCCEED; |
133 | } |
134 | |
135 | str |
136 | CMDbbpCount(bat *ret) |
137 | { |
138 | BAT *b, *bn; |
139 | int i; |
140 | lng l; |
141 | |
142 | b = COLnew(0, TYPE_lng, getBBPsize(), TRANSIENT); |
143 | if (b == 0) |
144 | throw(MAL, "catalog.bbpCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
145 | |
146 | for (i = 1; i < getBBPsize(); i++) |
147 | if (i != b->batCacheid) { |
148 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
149 | bn = BATdescriptor(i); |
150 | if (bn) { |
151 | l = BATcount(bn); |
152 | BBPunfix(bn->batCacheid); |
153 | if (BUNappend(b, &l, false) != GDK_SUCCEED) { |
154 | BBPreclaim(b); |
155 | throw(MAL, "catalog.bbpCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
156 | } |
157 | } |
158 | } |
159 | } |
160 | if (pseudo(ret,b,"bbp" ,"count" )) |
161 | throw(MAL, "catalog.bbpCount" , GDK_EXCEPTION); |
162 | return MAL_SUCCEED; |
163 | } |
164 | |
165 | /* |
166 | * The BAT status is redundantly stored in CMDbat_info. |
167 | */ |
168 | str |
169 | CMDbbpLocation(bat *ret) |
170 | { |
171 | BAT *b; |
172 | int i; |
173 | char buf[FILENAME_MAX]; |
174 | char cwd[FILENAME_MAX]; |
175 | |
176 | if (getcwd(cwd, FILENAME_MAX) == NULL) |
177 | throw(MAL, "catalog.bbpLocation" , RUNTIME_DIR_ERROR); |
178 | |
179 | b = COLnew(0, TYPE_str, getBBPsize(), TRANSIENT); |
180 | if (b == 0) |
181 | throw(MAL, "catalog.bbpLocation" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
182 | |
183 | BBPlock(); |
184 | for (i = 1; i < getBBPsize(); i++) |
185 | if (i != b->batCacheid) { |
186 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
187 | int len = snprintf(buf,FILENAME_MAX,"%s/bat/%s" ,cwd,BBP_physical(i)); |
188 | if (len == -1 || len >= FILENAME_MAX) { |
189 | BBPunlock(); |
190 | BBPreclaim(b); |
191 | throw(MAL, "catalog.bbpLocation" , SQLSTATE(HY001) "Could not write bpp filename path is too large" ); |
192 | } |
193 | if (BUNappend(b, buf, false) != GDK_SUCCEED) { |
194 | BBPunlock(); |
195 | BBPreclaim(b); |
196 | throw(MAL, "catalog.bbpLocation" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
197 | } |
198 | } |
199 | } |
200 | BBPunlock(); |
201 | if (pseudo(ret,b,"bbp" ,"location" )) |
202 | throw(MAL, "catalog.bbpLocation" , GDK_EXCEPTION); |
203 | return MAL_SUCCEED; |
204 | } |
205 | |
206 | /* |
207 | * The BAT dirty status:dirty => (mem != disk); diffs = not-committed |
208 | */ |
209 | str |
210 | CMDbbpDirty(bat *ret) |
211 | { |
212 | BAT *b; |
213 | int i; |
214 | |
215 | b = COLnew(0, TYPE_str, getBBPsize(), TRANSIENT); |
216 | if (b == 0) |
217 | throw(MAL, "catalog.bbpDirty" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
218 | |
219 | BBPlock(); |
220 | for (i = 1; i < getBBPsize(); i++) |
221 | if (i != b->batCacheid) |
222 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
223 | BAT *bn = BBP_cache(i); |
224 | |
225 | if (BUNappend(b, bn ? BATdirty(bn) ? "dirty" : DELTAdirty(bn) ? "diffs" : "clean" : (BBP_status(i) & BBPSWAPPED) ? "diffs" : "clean" , false) != GDK_SUCCEED) { |
226 | BBPunlock(); |
227 | BBPreclaim(b); |
228 | throw(MAL, "catalog.bbpDirty" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
229 | } |
230 | } |
231 | BBPunlock(); |
232 | if (pseudo(ret,b,"bbp" ,"status" )) |
233 | throw(MAL, "catalog.bbpDirty" , GDK_EXCEPTION); |
234 | return MAL_SUCCEED; |
235 | } |
236 | |
237 | /* |
238 | * The BAT status is redundantly stored in CMDbat_info. |
239 | */ |
240 | str |
241 | CMDbbpStatus(bat *ret) |
242 | { |
243 | BAT *b; |
244 | int i; |
245 | |
246 | b = COLnew(0, TYPE_str, getBBPsize(), TRANSIENT); |
247 | if (b == 0) |
248 | throw(MAL, "catalog.bbpStatus" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
249 | |
250 | BBPlock(); |
251 | for (i = 1; i < getBBPsize(); i++) |
252 | if (i != b->batCacheid) |
253 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
254 | char *loc = BBP_cache(i) ? "load" : "disk" ; |
255 | |
256 | if (BUNappend(b, loc, false) != GDK_SUCCEED) { |
257 | BBPunlock(); |
258 | BBPreclaim(b); |
259 | throw(MAL, "catalog.bbpStatus" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
260 | } |
261 | } |
262 | BBPunlock(); |
263 | if (pseudo(ret,b,"bbp" ,"status" )) |
264 | throw(MAL, "catalog.bbpStatus" , GDK_EXCEPTION); |
265 | return MAL_SUCCEED; |
266 | } |
267 | |
268 | str |
269 | CMDbbpKind(bat *ret) |
270 | { |
271 | BAT *b; |
272 | int i; |
273 | |
274 | b = COLnew(0, TYPE_str, getBBPsize(), TRANSIENT); |
275 | if (b == 0) |
276 | throw(MAL, "catalog.bbpKind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
277 | |
278 | BBPlock(); |
279 | for (i = 1; i < getBBPsize(); i++) |
280 | if (i != b->batCacheid && BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
281 | const char *mode; |
282 | |
283 | if ((BBP_status(i) & BBPDELETED) || !(BBP_status(i) & BBPPERSISTENT)) |
284 | mode = "transient" ; |
285 | else |
286 | mode = "persistent" ; |
287 | if (BUNappend(b, mode, false) != GDK_SUCCEED) { |
288 | BBPunlock(); |
289 | BBPreclaim(b); |
290 | throw(MAL, "catalog.bbpKind" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
291 | } |
292 | } |
293 | BBPunlock(); |
294 | if (pseudo(ret,b,"bbp" ,"kind" )) |
295 | throw(MAL, "catalog.bbpKind" , GDK_EXCEPTION); |
296 | return MAL_SUCCEED; |
297 | } |
298 | |
299 | str |
300 | CMDbbpRefCount(bat *ret) |
301 | { |
302 | BAT *b; |
303 | int i; |
304 | |
305 | b = COLnew(0, TYPE_int, getBBPsize(), TRANSIENT); |
306 | if (b == 0) |
307 | throw(MAL, "catalog.bbpRefCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
308 | |
309 | BBPlock(); |
310 | for (i = 1; i < getBBPsize(); i++) |
311 | if (i != b->batCacheid && BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
312 | int refs = BBP_refs(i); |
313 | |
314 | if (BUNappend(b, &refs, false) != GDK_SUCCEED) { |
315 | BBPunlock(); |
316 | BBPreclaim(b); |
317 | throw(MAL, "catalog.bbpRefCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
318 | } |
319 | } |
320 | BBPunlock(); |
321 | if (pseudo(ret,b,"bbp" ,"refcnt" )) |
322 | throw(MAL, "catalog.bbpRefCount" , GDK_EXCEPTION); |
323 | return MAL_SUCCEED; |
324 | } |
325 | |
326 | str |
327 | CMDbbpLRefCount(bat *ret) |
328 | { |
329 | BAT *b; |
330 | int i; |
331 | |
332 | b = COLnew(0, TYPE_int, getBBPsize(), TRANSIENT); |
333 | if (b == 0) |
334 | throw(MAL, "catalog.bbpLRefCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
335 | |
336 | BBPlock(); |
337 | for (i = 1; i < getBBPsize(); i++) |
338 | if (i != b->batCacheid && BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
339 | int refs = BBP_lrefs(i); |
340 | |
341 | if (BUNappend(b, &refs, false) != GDK_SUCCEED) { |
342 | BBPunlock(); |
343 | BBPreclaim(b); |
344 | throw(MAL, "catalog.bbpLRefCount" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
345 | } |
346 | } |
347 | BBPunlock(); |
348 | if (pseudo(ret,b,"bbp" ,"lrefcnt" )) |
349 | throw(MAL, "catalog.bbpLRefCount" , GDK_EXCEPTION); |
350 | return MAL_SUCCEED; |
351 | } |
352 | |
353 | str |
354 | CMDbbpgetIndex(int *res, bat *bid) |
355 | { |
356 | *res= *bid; |
357 | return MAL_SUCCEED; |
358 | } |
359 | |
360 | str |
361 | CMDgetBATrefcnt(int *res, bat *bid) |
362 | { |
363 | BAT *b; |
364 | |
365 | if ((b = BATdescriptor(*bid)) == NULL) { |
366 | throw(MAL, "bbp.getRefCount" , INTERNAL_BAT_ACCESS); |
367 | } |
368 | *res = BBP_refs(b->batCacheid); |
369 | BBPunfix(b->batCacheid); |
370 | return MAL_SUCCEED; |
371 | } |
372 | |
373 | str |
374 | CMDgetBATlrefcnt(int *res, bat *bid) |
375 | { |
376 | BAT *b; |
377 | |
378 | if ((b = BATdescriptor(*bid)) == NULL) { |
379 | throw(MAL, "bbp.getLRefCount" , INTERNAL_BAT_ACCESS); |
380 | } |
381 | *res = BBP_lrefs(b->batCacheid); |
382 | BBPunfix(b->batCacheid); |
383 | return MAL_SUCCEED; |
384 | } |
385 | |
386 | str CMDbbp(bat *ID, bat *NS, bat *TT, bat *CNT, bat *REFCNT, bat *LREFCNT, bat *LOCATION, bat *HEAT, bat *DIRTY, bat *STATUS, bat *KIND) |
387 | { |
388 | BAT *id, *ns, *tt, *cnt, *refcnt, *lrefcnt, *location, *heat, *dirty, *status, *kind, *bn; |
389 | bat i; |
390 | char buf[FILENAME_MAX]; |
391 | bat sz = getBBPsize(); |
392 | str msg = MAL_SUCCEED; |
393 | |
394 | id = COLnew(0, TYPE_int, (BUN) sz, TRANSIENT); |
395 | ns = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
396 | tt = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
397 | cnt = COLnew(0, TYPE_lng, (BUN) sz, TRANSIENT); |
398 | refcnt = COLnew(0, TYPE_int, (BUN) sz, TRANSIENT); |
399 | lrefcnt = COLnew(0, TYPE_int, (BUN) sz, TRANSIENT); |
400 | location = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
401 | heat = COLnew(0, TYPE_int, (BUN) sz, TRANSIENT); |
402 | dirty = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
403 | status = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
404 | kind = COLnew(0, TYPE_str, (BUN) sz, TRANSIENT); |
405 | |
406 | if (!id || !ns || !tt || !cnt || !refcnt || !lrefcnt || !location || !heat || !dirty || !status || !kind) { |
407 | goto bailout; |
408 | } |
409 | for (i = 1; i < sz; i++) { |
410 | if (BBP_logical(i) && (BBP_refs(i) || BBP_lrefs(i))) { |
411 | bn = BATdescriptor(i); |
412 | if (bn) { |
413 | lng l = BATcount(bn); |
414 | int heat_ = 0, len; |
415 | char *loc = BBP_cache(i) ? "load" : "disk" ; |
416 | char *mode = "persistent" ; |
417 | int refs = BBP_refs(i); |
418 | int lrefs = BBP_lrefs(i); |
419 | |
420 | if ((BBP_status(i) & BBPDELETED) || !(BBP_status(i) & BBPPERSISTENT)) |
421 | mode = "transient" ; |
422 | len = snprintf(buf, FILENAME_MAX, "%s" , BBP_physical(i)); |
423 | if (len == -1 || len >= FILENAME_MAX) { |
424 | msg = createException(MAL, "catalog.bbp" , SQLSTATE(HY001) "Could not bpp filename path is too large" ); |
425 | goto bailout; |
426 | } |
427 | if (BUNappend(id, &i, false) != GDK_SUCCEED || |
428 | BUNappend(ns, BBP_logical(i), false) != GDK_SUCCEED || |
429 | BUNappend(tt, BATatoms[BATttype(bn)].name, false) != GDK_SUCCEED || |
430 | BUNappend(cnt, &l, false) != GDK_SUCCEED || |
431 | BUNappend(refcnt, &refs, false) != GDK_SUCCEED || |
432 | BUNappend(lrefcnt, &lrefs, false) != GDK_SUCCEED || |
433 | BUNappend(location, buf, false) != GDK_SUCCEED || |
434 | BUNappend(heat, &heat_, false) != GDK_SUCCEED || |
435 | BUNappend(dirty, bn ? BATdirty(bn) ? "dirty" : DELTAdirty(bn) ? "diffs" : "clean" : (BBP_status(i) & BBPSWAPPED) ? "diffs" : "clean" , false) != GDK_SUCCEED || |
436 | BUNappend(status, loc, false) != GDK_SUCCEED || |
437 | BUNappend(kind, mode, false) != GDK_SUCCEED) { |
438 | BBPunfix(bn->batCacheid); |
439 | msg = createException(MAL, "catalog.bbp" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
440 | goto bailout; |
441 | } |
442 | BBPunfix(bn->batCacheid); |
443 | } |
444 | } |
445 | } |
446 | BBPkeepref(*ID = id->batCacheid); |
447 | BBPkeepref(*NS = ns->batCacheid); |
448 | BBPkeepref(*TT = tt->batCacheid); |
449 | BBPkeepref(*CNT = cnt->batCacheid); |
450 | BBPkeepref(*REFCNT = refcnt->batCacheid); |
451 | BBPkeepref(*LREFCNT = lrefcnt->batCacheid); |
452 | BBPkeepref(*LOCATION = location->batCacheid); |
453 | BBPkeepref(*HEAT = heat->batCacheid); |
454 | BBPkeepref(*DIRTY = dirty->batCacheid); |
455 | BBPkeepref(*STATUS = status->batCacheid); |
456 | BBPkeepref(*KIND = kind->batCacheid); |
457 | return MAL_SUCCEED; |
458 | |
459 | bailout: |
460 | BBPreclaim(id); |
461 | BBPreclaim(ns); |
462 | BBPreclaim(tt); |
463 | BBPreclaim(cnt); |
464 | BBPreclaim(refcnt); |
465 | BBPreclaim(lrefcnt); |
466 | BBPreclaim(location); |
467 | BBPreclaim(heat); |
468 | BBPreclaim(dirty); |
469 | BBPreclaim(status); |
470 | BBPreclaim(kind); |
471 | return msg; |
472 | } |
473 | |
474 | str |
475 | CMDsetName(str *rname, const bat *bid, str *name) |
476 | { |
477 | BAT *b; |
478 | if ((b = BATdescriptor(*bid)) == NULL) { |
479 | throw(MAL, "bbp.setName" , INTERNAL_BAT_ACCESS); |
480 | } |
481 | if (BBPrename(b->batCacheid, *name) != 0) { |
482 | BBPunfix(b->batCacheid); |
483 | throw(MAL, "bbp.setName" , GDK_EXCEPTION); |
484 | } |
485 | *rname = GDKstrdup(*name); |
486 | BBPunfix(b->batCacheid); |
487 | if (*rname == NULL) |
488 | throw(MAL, "bbp.setName" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
489 | return MAL_SUCCEED; |
490 | } |
491 | |