1 | /* |
2 | * PROGRAM: JRD access method |
3 | * MODULE: jrd.h |
4 | * DESCRIPTION: Common descriptions |
5 | * |
6 | * The contents of this file are subject to the Interbase Public |
7 | * License Version 1.0 (the "License"); you may not use this file |
8 | * except in compliance with the License. You may obtain a copy |
9 | * of the License at http://www.Inprise.com/IPL.html |
10 | * |
11 | * Software distributed under the License is distributed on an |
12 | * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express |
13 | * or implied. See the License for the specific language governing |
14 | * rights and limitations under the License. |
15 | * |
16 | * The Original Code was created by Inprise Corporation |
17 | * and its predecessors. Portions created by Inprise Corporation are |
18 | * Copyright (C) Inprise Corporation. |
19 | * |
20 | * All Rights Reserved. |
21 | * Contributor(s): ______________________________________. |
22 | * |
23 | * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port |
24 | * |
25 | * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port |
26 | * Claudio Valderrama C. |
27 | * Adriano dos Santos Fernandes |
28 | * |
29 | */ |
30 | |
31 | #ifndef JRD_JRD_H |
32 | #define JRD_JRD_H |
33 | |
34 | #include "../common/gdsassert.h" |
35 | #include "../common/dsc.h" |
36 | #include "../jrd/err_proto.h" |
37 | #include "../jrd/jrd_proto.h" |
38 | #include "../jrd/obj.h" |
39 | #include "../jrd/val.h" |
40 | |
41 | #include "../common/classes/fb_atomic.h" |
42 | #include "../common/classes/fb_string.h" |
43 | #include "../common/classes/MetaName.h" |
44 | #include "../common/classes/NestConst.h" |
45 | #include "../common/classes/array.h" |
46 | #include "../common/classes/objects_array.h" |
47 | #include "../common/classes/stack.h" |
48 | #include "../common/classes/timestamp.h" |
49 | #include "../common/classes/GenericMap.h" |
50 | #include "../common/classes/Synchronize.h" |
51 | #include "../common/utils_proto.h" |
52 | #include "../common/StatusHolder.h" |
53 | #include "../jrd/RandomGenerator.h" |
54 | #include "../common/os/guid.h" |
55 | #include "../jrd/sbm.h" |
56 | #include "../jrd/scl.h" |
57 | #include "../jrd/Routine.h" |
58 | #include "../jrd/ExtEngineManager.h" |
59 | #include "../jrd/Attachment.h" |
60 | #include "firebird/Provider.h" |
61 | |
62 | #ifdef DEV_BUILD |
63 | //#define DEBUG if (debug) DBG_supervisor(debug); |
64 | #else // PROD |
65 | //#define DEBUG |
66 | #endif |
67 | #define DEBUG |
68 | |
69 | #define BUGCHECK(number) ERR_bugcheck (number, __FILE__, __LINE__) |
70 | #define CORRUPT(number) ERR_corrupt (number) |
71 | #define IBERROR(number) ERR_error (number) |
72 | |
73 | |
74 | #define BLKCHK(blk, type) if (!blk->checkHandle()) BUGCHECK(147) |
75 | |
76 | #define DEV_BLKCHK(blk, type) do { } while (false) // nothing |
77 | |
78 | |
79 | // Thread data block / IPC related data blocks |
80 | #include "../common/ThreadData.h" |
81 | |
82 | // Definition of block types for data allocation in JRD |
83 | #include "../include/fb_blk.h" |
84 | |
85 | #include "../jrd/blb.h" |
86 | |
87 | // Definition of DatabasePlugins |
88 | #include "../jrd/flu.h" |
89 | |
90 | #include "../jrd/pag.h" |
91 | |
92 | #include "../jrd/RuntimeStatistics.h" |
93 | #include "../jrd/Database.h" |
94 | #include "../jrd/lck.h" |
95 | |
96 | // Error codes |
97 | #include "gen/iberror.h" |
98 | |
99 | struct dsc; |
100 | |
101 | namespace EDS { |
102 | class Connection; |
103 | } |
104 | |
105 | namespace Jrd { |
106 | |
107 | const int QUANTUM = 100; // Default quantum |
108 | const int SWEEP_QUANTUM = 10; // Make sweeps less disruptive |
109 | const unsigned MAX_CALLBACKS = 50; |
110 | |
111 | // fwd. decl. |
112 | class thread_db; |
113 | class Attachment; |
114 | class jrd_tra; |
115 | class jrd_req; |
116 | class JrdStatement; |
117 | class jrd_file; |
118 | class Format; |
119 | class BufferDesc; |
120 | class SparseBitmap; |
121 | class jrd_rel; |
122 | class ExternalFile; |
123 | class ViewContext; |
124 | class IndexBlock; |
125 | class IndexLock; |
126 | class ArrayField; |
127 | struct sort_context; |
128 | class vcl; |
129 | class TextType; |
130 | class Parameter; |
131 | class jrd_fld; |
132 | class dsql_dbb; |
133 | class PreparedStatement; |
134 | class TraceManager; |
135 | class MessageNode; |
136 | |
137 | // The database block, the topmost block in the metadata |
138 | // cache for a database |
139 | |
140 | // Relation trigger definition |
141 | |
142 | class Trigger |
143 | { |
144 | public: |
145 | Firebird::HalfStaticArray<UCHAR, 128> blr; // BLR code |
146 | bid dbg_blob_id; // RDB$DEBUG_INFO |
147 | JrdStatement* statement; // Compiled statement |
148 | bool compile_in_progress; |
149 | bool sys_trigger; |
150 | FB_UINT64 type; // Trigger type |
151 | USHORT flags; // Flags as they are in RDB$TRIGGERS table |
152 | jrd_rel* relation; // Trigger parent relation |
153 | Firebird::MetaName name; // Trigger name |
154 | Firebird::MetaName engine; // External engine name |
155 | Firebird::string entryPoint; // External trigger entrypoint |
156 | Firebird::string extBody; // External trigger body |
157 | ExtEngineManager::Trigger* extTrigger; // External trigger |
158 | |
159 | void compile(thread_db*); // Ensure that trigger is compiled |
160 | void release(thread_db*); // Try to free trigger request |
161 | |
162 | explicit Trigger(MemoryPool& p) |
163 | : blr(p), |
164 | name(p), |
165 | engine(p), |
166 | entryPoint(p), |
167 | extBody(p), |
168 | extTrigger(NULL) |
169 | { |
170 | dbg_blob_id.clear(); |
171 | } |
172 | }; |
173 | |
174 | |
175 | // |
176 | // Flags to indicate normal internal requests vs. dyn internal requests |
177 | // |
178 | const int IRQ_REQUESTS = 1; |
179 | const int DYN_REQUESTS = 2; |
180 | |
181 | |
182 | // |
183 | // Errors during validation - will be returned on info calls |
184 | // CVC: It seems they will be better in a header for val.cpp that's not val.h |
185 | // |
186 | const int VAL_PAG_WRONG_TYPE = 0; |
187 | const int VAL_PAG_CHECKSUM_ERR = 1; |
188 | const int VAL_PAG_DOUBLE_ALLOC = 2; |
189 | const int VAL_PAG_IN_USE = 3; |
190 | const int VAL_PAG_ORPHAN = 4; |
191 | const int VAL_BLOB_INCONSISTENT = 5; |
192 | const int VAL_BLOB_CORRUPT = 6; |
193 | const int VAL_BLOB_TRUNCATED = 7; |
194 | const int VAL_REC_CHAIN_BROKEN = 8; |
195 | const int VAL_DATA_PAGE_CONFUSED = 9; |
196 | const int VAL_DATA_PAGE_LINE_ERR = 10; |
197 | const int VAL_INDEX_PAGE_CORRUPT = 11; |
198 | const int VAL_P_PAGE_LOST = 12; |
199 | const int VAL_P_PAGE_INCONSISTENT = 13; |
200 | const int VAL_REC_DAMAGED = 14; |
201 | const int VAL_REC_BAD_TID = 15; |
202 | const int VAL_REC_FRAGMENT_CORRUPT = 16; |
203 | const int VAL_REC_WRONG_LENGTH = 17; |
204 | const int VAL_INDEX_ROOT_MISSING = 18; |
205 | const int VAL_TIP_LOST = 19; |
206 | const int VAL_TIP_LOST_SEQUENCE = 20; |
207 | const int VAL_TIP_CONFUSED = 21; |
208 | const int VAL_REL_CHAIN_ORPHANS = 22; |
209 | const int VAL_INDEX_MISSING_ROWS = 23; |
210 | const int VAL_INDEX_ORPHAN_CHILD = 24; |
211 | const int VAL_INDEX_CYCLE = 25; |
212 | const int VAL_SCNS_PAGE_INCONSISTENT = 26; |
213 | const int VAL_PAG_WRONG_SCN = 27; |
214 | const int VAL_BLOB_UNKNOWN_LEVEL = 28; |
215 | const int VAL_MAX_ERROR = 29; |
216 | |
217 | |
218 | // Procedure block |
219 | |
220 | class jrd_prc : public Routine |
221 | { |
222 | public: |
223 | ///const MessageNode* prc_output_msg; |
224 | const Format* prc_record_format; |
225 | prc_t prc_type; // procedure type |
226 | |
227 | const ExtEngineManager::Procedure* getExternal() const { return prc_external; } |
228 | void setExternal(ExtEngineManager::Procedure* value) { prc_external = value; } |
229 | |
230 | private: |
231 | const ExtEngineManager::Procedure* prc_external; |
232 | |
233 | public: |
234 | explicit jrd_prc(MemoryPool& p) |
235 | : Routine(p), |
236 | ///prc_output_msg(NULL), |
237 | prc_record_format(NULL), |
238 | prc_type(prc_legacy), |
239 | prc_external(NULL) |
240 | { |
241 | } |
242 | |
243 | public: |
244 | virtual int getObjectType() const |
245 | { |
246 | return obj_procedure; |
247 | } |
248 | |
249 | virtual SLONG getSclType() const |
250 | { |
251 | return SCL_object_procedure; |
252 | } |
253 | |
254 | virtual void releaseFormat() |
255 | { |
256 | delete prc_record_format; |
257 | prc_record_format = NULL; |
258 | } |
259 | |
260 | virtual bool checkCache(thread_db* tdbb) const; |
261 | virtual void clearCache(thread_db* tdbb); |
262 | }; |
263 | |
264 | |
265 | // Parameter block |
266 | |
267 | class Parameter : public pool_alloc<type_prm> |
268 | { |
269 | public: |
270 | USHORT prm_number; |
271 | dsc prm_desc; |
272 | NestConst<ValueExprNode> prm_default_value; |
273 | bool prm_nullable; |
274 | prm_mech_t prm_mechanism; |
275 | Firebird::MetaName prm_name; // asciiz name |
276 | Firebird::MetaName prm_field_source; |
277 | FUN_T prm_fun_mechanism; |
278 | |
279 | public: |
280 | explicit Parameter(MemoryPool& p) |
281 | : prm_name(p), |
282 | prm_field_source(p) |
283 | { |
284 | } |
285 | }; |
286 | |
287 | // Index block to cache index information |
288 | |
289 | class IndexBlock : public pool_alloc<type_idb> |
290 | { |
291 | public: |
292 | IndexBlock* idb_next; |
293 | ValueExprNode* idb_expression; // node tree for index expression |
294 | JrdStatement* idb_expression_statement; // statement for index expression evaluation |
295 | dsc idb_expression_desc; // descriptor for expression result |
296 | Lock* idb_lock; // lock to synchronize changes to index |
297 | USHORT idb_id; |
298 | }; |
299 | |
300 | |
301 | // |
302 | // Transaction element block |
303 | // |
304 | struct teb |
305 | { |
306 | Attachment* teb_database; |
307 | int teb_tpb_length; |
308 | const UCHAR* teb_tpb; |
309 | }; |
310 | |
311 | typedef teb TEB; |
312 | |
313 | // Window block for loading cached pages into |
314 | // CVC: Apparently, the only possible values are HEADER_PAGE==0 and LOG_PAGE==2 |
315 | // and reside in ods.h, although I watched a place with 1 and others with members |
316 | // of a struct. |
317 | |
318 | struct win |
319 | { |
320 | PageNumber win_page; |
321 | Ods::pag* win_buffer; |
322 | class BufferDesc* win_bdb; |
323 | SSHORT win_scans; |
324 | USHORT win_flags; |
325 | explicit win(const PageNumber& wp) |
326 | : win_page(wp), win_bdb(NULL), win_flags(0) |
327 | {} |
328 | win(const USHORT pageSpaceID, const SLONG pageNum) |
329 | : win_page(pageSpaceID, pageNum), win_bdb(NULL), win_flags(0) |
330 | {} |
331 | }; |
332 | |
333 | typedef win WIN; |
334 | |
335 | // This is a compilation artifact: I wanted to be sure I would pick all old "win" |
336 | // declarations at the top, so "win" was built with a mandatory argument in |
337 | // the constructor. This struct satisfies a single place with an array. The |
338 | // alternative would be to initialize 16 elements of the array with 16 calls |
339 | // to the constructor: win my_array[n] = {win(-1), ... (win-1)}; |
340 | // When all places are changed, this class can disappear and win's constructor |
341 | // may get the default value of -1 to "wp". |
342 | struct win_for_array: public win |
343 | { |
344 | win_for_array() |
345 | : win(DB_PAGE_SPACE, -1) |
346 | {} |
347 | }; |
348 | |
349 | // win_flags |
350 | |
351 | const USHORT WIN_large_scan = 1; // large sequential scan |
352 | const USHORT WIN_secondary = 2; // secondary stream |
353 | const USHORT WIN_garbage_collector = 4; // garbage collector's window |
354 | const USHORT WIN_garbage_collect = 8; // scan left a page for garbage collector |
355 | |
356 | |
357 | // Thread specific database block |
358 | |
359 | // tdbb_flags |
360 | |
361 | const USHORT TDBB_sweeper = 1; // Thread sweeper or garbage collector |
362 | const USHORT TDBB_no_cache_unwind = 2; // Don't unwind page buffer cache |
363 | const USHORT TDBB_backup_write_locked = 4; // BackupManager has write lock on LCK_backup_database |
364 | const USHORT TDBB_stack_trace_done = 8; // PSQL stack trace is added into status-vector |
365 | const USHORT TDBB_shutdown_manager = 16; // Server shutdown thread |
366 | const USHORT TDBB_dont_post_dfw = 32; // dont post DFW tasks as deferred work is performed now |
367 | const USHORT TDBB_sys_error = 64; // error shouldn't be handled by the looper |
368 | const USHORT TDBB_verb_cleanup = 128; // verb cleanup is in progress |
369 | const USHORT TDBB_use_db_page_space = 256; // use database (not temporary) page space in GTT operations |
370 | const USHORT TDBB_detaching = 512; // detach is in progress |
371 | const USHORT TDBB_wait_cancel_disable = 1024; // don't cancel current waiting operation |
372 | const USHORT TDBB_cache_unwound = 2048; // page cache was unwound |
373 | |
374 | class thread_db : public Firebird::ThreadData |
375 | { |
376 | private: |
377 | MemoryPool* defaultPool; |
378 | void setDefaultPool(MemoryPool* p) |
379 | { |
380 | defaultPool = p; |
381 | } |
382 | friend class Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool>; |
383 | Database* database; |
384 | Attachment* attachment; |
385 | jrd_tra* transaction; |
386 | jrd_req* request; |
387 | RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat; |
388 | thread_db *priorThread, *nextThread; |
389 | |
390 | public: |
391 | explicit thread_db(ISC_STATUS* status) |
392 | : ThreadData(ThreadData::tddDBB), |
393 | defaultPool(NULL), |
394 | database(NULL), |
395 | attachment(NULL), |
396 | transaction(NULL), |
397 | request(NULL), |
398 | priorThread(NULL), |
399 | nextThread(NULL), |
400 | tdbb_status_vector(status), |
401 | tdbb_quantum(QUANTUM), |
402 | tdbb_flags(0), |
403 | tdbb_temp_traid(0), |
404 | tdbb_bdbs(*getDefaultMemoryPool()), |
405 | tdbb_thread(Firebird::ThreadSync::getThread("thread_db" )) |
406 | { |
407 | reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy(); |
408 | fb_utils::init_status(tdbb_status_vector); |
409 | } |
410 | |
411 | ~thread_db() |
412 | { |
413 | #ifdef DEV_BUILD |
414 | for (size_t n = 0; n < tdbb_bdbs.getCount(); ++n) |
415 | { |
416 | fb_assert(tdbb_bdbs[n] == NULL); |
417 | } |
418 | #endif |
419 | } |
420 | |
421 | ISC_STATUS* tdbb_status_vector; |
422 | SSHORT tdbb_quantum; // Cycles remaining until voluntary schedule |
423 | USHORT tdbb_flags; |
424 | |
425 | TraNumber tdbb_temp_traid; // current temporary table scope |
426 | |
427 | // BDB's held by thread |
428 | Firebird::HalfStaticArray<BufferDesc*, 16> tdbb_bdbs; |
429 | Firebird::ThreadSync* tdbb_thread; |
430 | |
431 | MemoryPool* getDefaultPool() |
432 | { |
433 | return defaultPool; |
434 | } |
435 | |
436 | Database* getDatabase() |
437 | { |
438 | return database; |
439 | } |
440 | |
441 | const Database* getDatabase() const |
442 | { |
443 | return database; |
444 | } |
445 | |
446 | void setDatabase(Database* val); |
447 | |
448 | Attachment* getAttachment() |
449 | { |
450 | return attachment; |
451 | } |
452 | |
453 | const Attachment* getAttachment() const |
454 | { |
455 | return attachment; |
456 | } |
457 | |
458 | void setAttachment(Attachment* val); |
459 | |
460 | jrd_tra* getTransaction() |
461 | { |
462 | return transaction; |
463 | } |
464 | |
465 | const jrd_tra* getTransaction() const |
466 | { |
467 | return transaction; |
468 | } |
469 | |
470 | void setTransaction(jrd_tra* val); |
471 | |
472 | jrd_req* getRequest() |
473 | { |
474 | return request; |
475 | } |
476 | |
477 | const jrd_req* getRequest() const |
478 | { |
479 | return request; |
480 | } |
481 | |
482 | void setRequest(jrd_req* val); |
483 | |
484 | SSHORT getCharSet() const; |
485 | |
486 | void bumpStats(const RuntimeStatistics::StatType index) |
487 | { |
488 | reqStat->bumpValue(index); |
489 | traStat->bumpValue(index); |
490 | attStat->bumpValue(index); |
491 | dbbStat->bumpValue(index); |
492 | } |
493 | |
494 | void bumpRelStats(const RelStatType index, SLONG relation_id) |
495 | { |
496 | reqStat->bumpRelValue(index, relation_id); |
497 | traStat->bumpRelValue(index, relation_id); |
498 | attStat->bumpRelValue(index, relation_id); |
499 | //dbbStat->bumpRelValue(index, relation_id); |
500 | } |
501 | |
502 | bool checkCancelState(bool punt); |
503 | |
504 | void registerBdb(BufferDesc* bdb) |
505 | { |
506 | if (tdbb_bdbs.isEmpty()) { |
507 | tdbb_flags &= ~TDBB_cache_unwound; |
508 | } |
509 | fb_assert(!(tdbb_flags & TDBB_cache_unwound)); |
510 | |
511 | size_t pos; |
512 | if (tdbb_bdbs.find(NULL, pos)) |
513 | tdbb_bdbs[pos] = bdb; |
514 | else |
515 | tdbb_bdbs.add(bdb); |
516 | } |
517 | |
518 | bool clearBdb(BufferDesc* bdb) |
519 | { |
520 | if (tdbb_bdbs.isEmpty()) |
521 | { |
522 | // hvlad: the only legal case when thread holds no latches but someone |
523 | // tried to release latch is when CCH_unwind was called (and released |
524 | // all latches) but caller is unaware about it. See CORE-3034, for example. |
525 | // Else it is bug and should be BUGCHECK'ed. |
526 | |
527 | if (tdbb_flags & TDBB_cache_unwound) |
528 | return false; |
529 | } |
530 | fb_assert(!(tdbb_flags & TDBB_cache_unwound)); |
531 | |
532 | size_t pos; |
533 | if (!tdbb_bdbs.find(bdb, pos)) |
534 | BUGCHECK(300); // can't find shared latch |
535 | |
536 | tdbb_bdbs[pos] = NULL; |
537 | |
538 | if (pos == tdbb_bdbs.getCount() - 1) |
539 | { |
540 | while (true) |
541 | { |
542 | if (tdbb_bdbs[pos] != NULL) |
543 | { |
544 | tdbb_bdbs.shrink(pos + 1); |
545 | break; |
546 | } |
547 | |
548 | if (pos == 0) |
549 | { |
550 | tdbb_bdbs.shrink(0); |
551 | break; |
552 | } |
553 | |
554 | --pos; |
555 | } |
556 | } |
557 | |
558 | return true; |
559 | } |
560 | |
561 | void activate() |
562 | { |
563 | fb_assert(!priorThread && !nextThread); |
564 | |
565 | if (database) |
566 | { |
567 | Firebird::SyncLockGuard sync(&database->dbb_threads_sync, Firebird::SYNC_EXCLUSIVE, |
568 | "thread_db::activate" ); |
569 | |
570 | if (database->dbb_active_threads) |
571 | { |
572 | fb_assert(!database->dbb_active_threads->priorThread); |
573 | database->dbb_active_threads->priorThread = this; |
574 | nextThread = database->dbb_active_threads; |
575 | } |
576 | |
577 | database->dbb_active_threads = this; |
578 | } |
579 | } |
580 | |
581 | void deactivate() |
582 | { |
583 | if (database) |
584 | { |
585 | Firebird::SyncLockGuard sync(&database->dbb_threads_sync, Firebird::SYNC_EXCLUSIVE, |
586 | "thread_db::deactivate" ); |
587 | |
588 | if (nextThread) |
589 | { |
590 | fb_assert(nextThread->priorThread == this); |
591 | nextThread->priorThread = priorThread; |
592 | } |
593 | |
594 | if (priorThread) |
595 | { |
596 | fb_assert(priorThread->nextThread == this); |
597 | priorThread->nextThread = nextThread; |
598 | } |
599 | else |
600 | { |
601 | fb_assert(database->dbb_active_threads == this); |
602 | database->dbb_active_threads = nextThread; |
603 | } |
604 | } |
605 | |
606 | priorThread = nextThread = NULL; |
607 | } |
608 | }; |
609 | |
610 | |
611 | class ThreadContextHolder |
612 | { |
613 | public: |
614 | explicit ThreadContextHolder(ISC_STATUS* status = NULL) |
615 | : context(status ? status : local_status), externStatus(NULL) |
616 | { |
617 | context.putSpecific(); |
618 | } |
619 | |
620 | explicit ThreadContextHolder(Firebird::IStatus* status) |
621 | : context(local_status), externStatus(status) |
622 | { |
623 | context.putSpecific(); |
624 | externStatus->init(); |
625 | } |
626 | |
627 | ThreadContextHolder(Database* dbb, Jrd::Attachment* att, ISC_STATUS* status = NULL) |
628 | : context(status ? status : local_status), externStatus(NULL) |
629 | { |
630 | context.putSpecific(); |
631 | context.setDatabase(dbb); |
632 | context.setAttachment(att); |
633 | } |
634 | |
635 | ~ThreadContextHolder() |
636 | { |
637 | unsigned l = fb_utils::statusLength(context.tdbb_status_vector); |
638 | if (externStatus && externStatus->isSuccess() && (l > 2 || context.tdbb_status_vector[1])) |
639 | { |
640 | externStatus->set(l, context.tdbb_status_vector); |
641 | } |
642 | Firebird::ThreadData::restoreSpecific(); |
643 | } |
644 | |
645 | thread_db* operator->() |
646 | { |
647 | return &context; |
648 | } |
649 | |
650 | operator thread_db*() |
651 | { |
652 | return &context; |
653 | } |
654 | |
655 | private: |
656 | // copying is prohibited |
657 | ThreadContextHolder(const ThreadContextHolder&); |
658 | ThreadContextHolder& operator= (const ThreadContextHolder&); |
659 | |
660 | ISC_STATUS_ARRAY local_status; |
661 | thread_db context; |
662 | Firebird::IStatus* externStatus; |
663 | }; |
664 | |
665 | |
666 | // CVC: This class was designed to restore the thread's default status vector automatically. |
667 | // In several places, tdbb_status_vector is replaced by a local temporary. |
668 | class ThreadStatusGuard |
669 | { |
670 | public: |
671 | explicit ThreadStatusGuard(thread_db* tdbb) |
672 | : m_tdbb(tdbb), m_old_status(tdbb->tdbb_status_vector) |
673 | { |
674 | fb_utils::init_status(m_local_status); |
675 | m_tdbb->tdbb_status_vector = m_local_status; |
676 | } |
677 | |
678 | ~ThreadStatusGuard() |
679 | { |
680 | m_tdbb->tdbb_status_vector = m_old_status; |
681 | } |
682 | |
683 | //ISC_STATUS* restore() |
684 | //{ |
685 | // return m_tdbb->tdbb_status_vector = m_old_status; // copy, not comparison |
686 | //} |
687 | |
688 | operator ISC_STATUS*() { return m_local_status; } |
689 | |
690 | void copyToOriginal() |
691 | { |
692 | memcpy(m_old_status, m_local_status, sizeof(ISC_STATUS_ARRAY)); |
693 | } |
694 | |
695 | private: |
696 | thread_db* const m_tdbb; |
697 | ISC_STATUS* const m_old_status; |
698 | ISC_STATUS_ARRAY m_local_status; |
699 | |
700 | // copying is prohibited |
701 | ThreadStatusGuard(const ThreadStatusGuard&); |
702 | ThreadStatusGuard& operator=(const ThreadStatusGuard&); |
703 | }; |
704 | |
705 | |
706 | // duplicate context of firebird string |
707 | inline char* stringDup(MemoryPool& p, const Firebird::string& s) |
708 | { |
709 | char* rc = (char*) p.allocate(s.length() + 1 |
710 | #ifdef DEBUG_GDS_ALLOC |
711 | , __FILE__, __LINE__ |
712 | #endif |
713 | ); |
714 | strcpy(rc, s.c_str()); |
715 | return rc; |
716 | } |
717 | |
718 | inline char* stringDup(MemoryPool& p, const char* s, size_t l) |
719 | { |
720 | char* rc = (char*) p.allocate(l + 1 |
721 | #ifdef DEBUG_GDS_ALLOC |
722 | , __FILE__, __LINE__ |
723 | #endif |
724 | ); |
725 | memcpy(rc, s, l); |
726 | rc[l] = 0; |
727 | return rc; |
728 | } |
729 | |
730 | inline char* stringDup(MemoryPool& p, const char* s) |
731 | { |
732 | if (! s) |
733 | { |
734 | return 0; |
735 | } |
736 | return stringDup(p, s, strlen(s)); |
737 | } |
738 | |
739 | // Used in string conversion calls |
740 | typedef Firebird::HalfStaticArray<UCHAR, 256> MoveBuffer; |
741 | |
742 | } //namespace Jrd |
743 | |
744 | // Threading macros |
745 | |
746 | /* Define JRD_get_thread_data off the platform specific version. |
747 | * If we're in DEV mode, also do consistancy checks on the |
748 | * retrieved memory structure. This was originally done to |
749 | * track down cases of no "PUT_THREAD_DATA" on the NLM. |
750 | * |
751 | * This allows for NULL thread data (which might be an error by itself) |
752 | * If there is thread data, |
753 | * AND it is tagged as being a thread_db. |
754 | * AND it has a non-NULL database field, |
755 | * THEN we validate that the structure there is a database block. |
756 | * Otherwise, we return what we got. |
757 | * We can't always validate the database field, as during initialization |
758 | * there is no database set up. |
759 | */ |
760 | |
761 | #if defined(DEV_BUILD) |
762 | #include "../jrd/err_proto.h" |
763 | |
764 | inline Jrd::thread_db* JRD_get_thread_data() |
765 | { |
766 | Firebird::ThreadData* p1 = Firebird::ThreadData::getSpecific(); |
767 | if (p1 && p1->getType() == Firebird::ThreadData::tddDBB) |
768 | { |
769 | Jrd::thread_db* p2 = (Jrd::thread_db*) p1; |
770 | if (p2->getDatabase() && !p2->getDatabase()->checkHandle()) |
771 | { |
772 | BUGCHECK(147); |
773 | } |
774 | } |
775 | return (Jrd::thread_db*) p1; |
776 | } |
777 | |
778 | inline void CHECK_TDBB(const Jrd::thread_db* tdbb) |
779 | { |
780 | fb_assert(tdbb && (tdbb->getType() == Firebird::ThreadData::tddDBB) && |
781 | (!tdbb->getDatabase() || tdbb->getDatabase()->checkHandle())); |
782 | } |
783 | |
784 | inline void CHECK_DBB(const Jrd::Database* dbb) |
785 | { |
786 | fb_assert(dbb && dbb->checkHandle()); |
787 | } |
788 | |
789 | #else // PROD_BUILD |
790 | |
791 | inline Jrd::thread_db* JRD_get_thread_data() |
792 | { |
793 | return (Jrd::thread_db*) Firebird::ThreadData::getSpecific(); |
794 | } |
795 | |
796 | inline void CHECK_DBB(const Jrd::Database*) |
797 | { |
798 | } |
799 | |
800 | inline void CHECK_TDBB(const Jrd::thread_db*) |
801 | { |
802 | } |
803 | |
804 | #endif |
805 | |
806 | inline Jrd::Database* GET_DBB() |
807 | { |
808 | return JRD_get_thread_data()->getDatabase(); |
809 | } |
810 | |
811 | /*-------------------------------------------------------------------------* |
812 | * macros used to set thread_db and Database pointers when there are not set already * |
813 | *-------------------------------------------------------------------------*/ |
814 | inline void SET_TDBB(Jrd::thread_db*& tdbb) |
815 | { |
816 | if (tdbb == NULL) { |
817 | tdbb = JRD_get_thread_data(); |
818 | } |
819 | CHECK_TDBB(tdbb); |
820 | } |
821 | |
822 | inline void SET_DBB(Jrd::Database*& dbb) |
823 | { |
824 | if (dbb == NULL) { |
825 | dbb = GET_DBB(); |
826 | } |
827 | CHECK_DBB(dbb); |
828 | } |
829 | |
830 | |
831 | // global variables for engine |
832 | |
833 | extern int debug; |
834 | |
835 | namespace Jrd { |
836 | typedef Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool> ContextPoolHolder; |
837 | |
838 | class DatabaseContextHolder : public Jrd::ContextPoolHolder |
839 | { |
840 | public: |
841 | explicit DatabaseContextHolder(thread_db* tdbb) |
842 | : Jrd::ContextPoolHolder(tdbb, tdbb->getDatabase()->dbb_permanent), |
843 | savedTdbb(tdbb) |
844 | { |
845 | savedTdbb->activate(); |
846 | } |
847 | |
848 | ~DatabaseContextHolder() |
849 | { |
850 | savedTdbb->deactivate(); |
851 | } |
852 | |
853 | private: |
854 | // copying is prohibited |
855 | DatabaseContextHolder(const DatabaseContextHolder&); |
856 | DatabaseContextHolder& operator=(const DatabaseContextHolder&); |
857 | |
858 | thread_db* const savedTdbb; |
859 | }; |
860 | |
861 | class BackgroundContextHolder : public ThreadContextHolder, public DatabaseContextHolder, |
862 | public Jrd::Attachment::SyncGuard |
863 | { |
864 | public: |
865 | BackgroundContextHolder(Database* dbb, Jrd::Attachment* att, ISC_STATUS* status, const char* f) |
866 | : ThreadContextHolder(dbb, att, status), |
867 | DatabaseContextHolder(operator thread_db*()), |
868 | Jrd::Attachment::SyncGuard(att, f) |
869 | {} |
870 | |
871 | private: |
872 | // copying is prohibited |
873 | BackgroundContextHolder(const BackgroundContextHolder&); |
874 | BackgroundContextHolder& operator=(const BackgroundContextHolder&); |
875 | }; |
876 | |
877 | class AstLockHolder : public Firebird::ReadLockGuard |
878 | { |
879 | public: |
880 | AstLockHolder(Database* dbb, const char* f) |
881 | : Firebird::ReadLockGuard(dbb->dbb_ast_lock, f) |
882 | { |
883 | if (dbb->dbb_flags & DBB_no_ast) |
884 | { |
885 | // usually to be swallowed by the AST, but it allows to skip its execution |
886 | Firebird::status_exception::raise(Firebird::Arg::Gds(isc_unavailable)); |
887 | } |
888 | } |
889 | }; |
890 | |
891 | class AsyncContextHolder : public AstLockHolder, public Jrd::Attachment::SyncGuard, |
892 | public ThreadContextHolder, public DatabaseContextHolder |
893 | { |
894 | public: |
895 | AsyncContextHolder(Database* dbb, const char* f, Lock* lck = NULL) |
896 | : AstLockHolder(dbb, f), |
897 | Jrd::Attachment::SyncGuard(lck ? |
898 | lck->getLockInterface() : Firebird::RefPtr<JAttachment>(), f, true), |
899 | ThreadContextHolder(dbb, lck ? lck->getLockAttachment() : NULL), |
900 | DatabaseContextHolder(operator thread_db*()) |
901 | {} |
902 | |
903 | private: |
904 | // copying is prohibited |
905 | AsyncContextHolder(const AsyncContextHolder&); |
906 | AsyncContextHolder& operator=(const AsyncContextHolder&); |
907 | }; |
908 | } |
909 | |
910 | #endif // JRD_JRD_H |
911 | |