1 | /* |
2 | * PROGRAM: JRD access method |
3 | * MODULE: Database.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 | * |
28 | */ |
29 | |
30 | #ifndef JRD_DATABASE_H |
31 | #define JRD_DATABASE_H |
32 | |
33 | #include "firebird.h" |
34 | #include "../jrd/cch.h" |
35 | #include "../common/gdsassert.h" |
36 | #include "../common/dsc.h" |
37 | #include "../jrd/btn.h" |
38 | #include "../jrd/jrd_proto.h" |
39 | #include "../jrd/val.h" |
40 | #include "../jrd/irq.h" |
41 | #include "../jrd/drq.h" |
42 | #include "../include/gen/iberror.h" |
43 | |
44 | #include "../common/classes/fb_atomic.h" |
45 | #include "../common/classes/fb_string.h" |
46 | #include "../common/classes/MetaName.h" |
47 | #include "../common/classes/array.h" |
48 | #include "../common/classes/objects_array.h" |
49 | #include "../common/classes/stack.h" |
50 | #include "../common/classes/timestamp.h" |
51 | #include "../common/classes/GenericMap.h" |
52 | #include "../common/classes/RefCounted.h" |
53 | #include "../common/classes/semaphore.h" |
54 | #include "../common/utils_proto.h" |
55 | #include "../jrd/RandomGenerator.h" |
56 | #include "../common/os/guid.h" |
57 | #include "../jrd/sbm.h" |
58 | #include "../jrd/flu.h" |
59 | #include "../jrd/RuntimeStatistics.h" |
60 | #include "../jrd/event_proto.h" |
61 | #include "../jrd/ExtEngineManager.h" |
62 | #include "../lock/lock_proto.h" |
63 | #include "../common/config/config.h" |
64 | #include "../common/classes/SyncObject.h" |
65 | #include "../common/classes/Synchronize.h" |
66 | #include "fb_types.h" |
67 | |
68 | namespace Jrd |
69 | { |
70 | template <typename T> class vec; |
71 | class jrd_rel; |
72 | class Shadow; |
73 | class BlobFilter; |
74 | class TipCache; |
75 | class BackupManager; |
76 | class ExternalFileDirectoryList; |
77 | class MonitoringData; |
78 | class GarbageCollector; |
79 | class CryptoManager; |
80 | |
81 | // general purpose vector |
82 | template <class T, BlockType TYPE = type_vec> |
83 | class vec_base : protected pool_alloc<TYPE> |
84 | { |
85 | public: |
86 | typedef typename Firebird::Array<T>::iterator iterator; |
87 | typedef typename Firebird::Array<T>::const_iterator const_iterator; |
88 | |
89 | /* |
90 | static vec_base* newVector(MemoryPool& p, int len) |
91 | { |
92 | return FB_NEW(p) vec_base<T, TYPE>(p, len); |
93 | } |
94 | |
95 | static vec_base* newVector(MemoryPool& p, const vec_base& base) |
96 | { |
97 | return FB_NEW(p) vec_base<T, TYPE>(p, base); |
98 | } |
99 | */ |
100 | |
101 | size_t count() const { return v.getCount(); } |
102 | T& operator[](size_t index) { return v[index]; } |
103 | const T& operator[](size_t index) const { return v[index]; } |
104 | |
105 | iterator begin() { return v.begin(); } |
106 | iterator end() { return v.end(); } |
107 | |
108 | const_iterator begin() const { return v.begin(); } |
109 | const_iterator end() const { return v.end(); } |
110 | |
111 | void clear() { v.clear(); } |
112 | |
113 | T* memPtr() { return &v[0]; } |
114 | |
115 | void resize(size_t n, T val = T()) { v.resize(n, val); } |
116 | |
117 | void operator delete(void* mem) { MemoryPool::globalFree(mem); } |
118 | |
119 | protected: |
120 | vec_base(MemoryPool& p, int len) |
121 | : v(p, len) |
122 | { |
123 | v.resize(len); |
124 | } |
125 | |
126 | vec_base(MemoryPool& p, const vec_base& base) |
127 | : v(p) |
128 | { |
129 | v = base.v; |
130 | } |
131 | |
132 | private: |
133 | Firebird::Array<T> v; |
134 | }; |
135 | |
136 | template <typename T> |
137 | class vec : public vec_base<T, type_vec> |
138 | { |
139 | public: |
140 | static vec* newVector(MemoryPool& p, int len) |
141 | { |
142 | return FB_NEW(p) vec<T>(p, len); |
143 | } |
144 | |
145 | static vec* newVector(MemoryPool& p, const vec& base) |
146 | { |
147 | return FB_NEW(p) vec<T>(p, base); |
148 | } |
149 | |
150 | static vec* newVector(MemoryPool& p, vec* base, int len) |
151 | { |
152 | if (!base) |
153 | base = FB_NEW(p) vec<T>(p, len); |
154 | else if (len > (int) base->count()) |
155 | base->resize(len); |
156 | return base; |
157 | } |
158 | |
159 | private: |
160 | vec(MemoryPool& p, int len) : vec_base<T, type_vec>(p, len) {} |
161 | vec(MemoryPool& p, const vec& base) : vec_base<T, type_vec>(p, base) {} |
162 | }; |
163 | |
164 | class vcl : public vec_base<ULONG, type_vcl> |
165 | { |
166 | public: |
167 | static vcl* newVector(MemoryPool& p, int len) |
168 | { |
169 | return FB_NEW(p) vcl(p, len); |
170 | } |
171 | |
172 | static vcl* newVector(MemoryPool& p, const vcl& base) |
173 | { |
174 | return FB_NEW(p) vcl(p, base); |
175 | } |
176 | |
177 | static vcl* newVector(MemoryPool& p, vcl* base, int len) |
178 | { |
179 | if (!base) |
180 | base = FB_NEW(p) vcl(p, len); |
181 | else if (len > (int) base->count()) |
182 | base->resize(len); |
183 | return base; |
184 | } |
185 | |
186 | private: |
187 | vcl(MemoryPool& p, int len) : vec_base<ULONG, type_vcl>(p, len) {} |
188 | vcl(MemoryPool& p, const vcl& base) : vec_base<ULONG, type_vcl>(p, base) {} |
189 | }; |
190 | |
191 | typedef vec<TraNumber> TransactionsVector; |
192 | |
193 | |
194 | // |
195 | // bit values for dbb_flags |
196 | // |
197 | const ULONG DBB_damaged = 0x1L; |
198 | const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode |
199 | const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred |
200 | const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists |
201 | const ULONG DBB_gc_active = 0x10L; // ... and is actively working. |
202 | const ULONG DBB_gc_pending = 0x20L; // garbage collection requested |
203 | const ULONG DBB_force_write = 0x40L; // Database is forced write |
204 | const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions |
205 | const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3 |
206 | const ULONG DBB_read_only = 0x200L; // DB is ReadOnly (RO). If not set, DB is RW |
207 | const ULONG DBB_being_opened_read_only = 0x400L; // DB is being opened RO. If unset, opened as RW |
208 | const ULONG DBB_no_ast = 0x800L; // AST delivery is prohibited |
209 | const ULONG DBB_sweep_in_progress = 0x1000L; // A database sweep operation is in progress |
210 | const ULONG DBB_security_db = 0x2000L; // ISC security database |
211 | const ULONG DBB_suspend_bgio = 0x4000L; // Suspend I/O by background threads |
212 | const ULONG DBB_new = 0x8000L; // Database object is just created |
213 | const ULONG DBB_gc_cooperative = 0x10000L; // cooperative garbage collection |
214 | const ULONG DBB_gc_background = 0x20000L; // background garbage collection by gc_thread |
215 | const ULONG DBB_no_fs_cache = 0x40000L; // Not using file system cache |
216 | const ULONG DBB_sweep_starting = 0x80000L; // Auto-sweep is starting |
217 | const ULONG DBB_creating = 0x100000L; // Database creation is in progress |
218 | |
219 | // |
220 | // dbb_ast_flags |
221 | // |
222 | const ULONG DBB_blocking = 0x1L; // Exclusive mode is blocking |
223 | const ULONG DBB_get_shadows = 0x2L; // Signal received to check for new shadows |
224 | const ULONG DBB_assert_locks = 0x4L; // Locks are to be asserted |
225 | const ULONG DBB_shutdown = 0x8L; // Database is shutdown |
226 | const ULONG DBB_shut_attach = 0x10L; // no new attachments accepted |
227 | const ULONG DBB_shut_tran = 0x20L; // no new transactions accepted |
228 | const ULONG DBB_shut_force = 0x40L; // forced shutdown in progress |
229 | const ULONG DBB_shutdown_full = 0x80L; // Database fully shut down |
230 | const ULONG DBB_shutdown_single = 0x100L; // Database is in single-user maintenance mode |
231 | const ULONG DBB_monitor_off = 0x200L; // Database has the monitoring lock released |
232 | |
233 | class Database : public pool_alloc<type_dbb> |
234 | { |
235 | public: |
236 | class SharedCounter |
237 | { |
238 | static const ULONG DEFAULT_CACHE_SIZE = 16; |
239 | |
240 | struct ValueCache |
241 | { |
242 | Lock* lock; // lock which holds shared counter value |
243 | SLONG curVal; // current value of shared counter lock |
244 | SLONG maxVal; // maximum cached value of shared counter lock |
245 | }; |
246 | |
247 | public: |
248 | enum |
249 | { |
250 | ATTACHMENT_ID_SPACE = 0, |
251 | TRANSACTION_ID_SPACE = 1, |
252 | STATEMENT_ID_SPACE = 2, |
253 | TOTAL_ITEMS = 3 |
254 | }; |
255 | |
256 | SharedCounter(); |
257 | ~SharedCounter(); |
258 | |
259 | SLONG generate(thread_db* tdbb, ULONG space, ULONG prefetch = DEFAULT_CACHE_SIZE); |
260 | void shutdown(thread_db* tdbb); |
261 | |
262 | private: |
263 | static int blockingAst(void* arg); |
264 | |
265 | ValueCache m_counters[TOTAL_ITEMS]; |
266 | }; |
267 | |
268 | class ExistenceRefMutex : public Firebird::RefCounted |
269 | { |
270 | public: |
271 | ExistenceRefMutex() |
272 | : exist(true) |
273 | { } |
274 | |
275 | ~ExistenceRefMutex() |
276 | { } |
277 | |
278 | public: |
279 | void destroy() |
280 | { |
281 | exist = false; |
282 | } |
283 | |
284 | bool doesExist() const |
285 | { |
286 | return exist; |
287 | } |
288 | |
289 | void enter() |
290 | { |
291 | mutex.enter("ExistenceRefMutex::enter()" ); |
292 | } |
293 | |
294 | void leave() |
295 | { |
296 | mutex.leave(); |
297 | } |
298 | |
299 | private: |
300 | Firebird::Mutex mutex; |
301 | bool exist; |
302 | }; |
303 | |
304 | class Linger FB_FINAL : public Firebird::RefCntIface<Firebird::ITimer, FB_TIMER_VERSION> |
305 | { |
306 | public: |
307 | explicit Linger(Database* a_dbb) |
308 | : dbb(a_dbb), active(false) |
309 | { } |
310 | |
311 | void set(unsigned seconds); |
312 | void reset(); |
313 | void destroy(); |
314 | |
315 | // ITimer implementation |
316 | void FB_CARG handler(); |
317 | int FB_CARG release(); |
318 | |
319 | private: |
320 | Database* dbb; |
321 | bool active; |
322 | }; |
323 | |
324 | static Database* create(Firebird::IPluginConfig* pConf) |
325 | { |
326 | Firebird::MemoryStats temp_stats; |
327 | MemoryPool* const pool = MemoryPool::createPool(NULL, temp_stats); |
328 | Database* const dbb = FB_NEW(*pool) Database(pool, pConf); |
329 | pool->setStatsGroup(dbb->dbb_memory_stats); |
330 | return dbb; |
331 | } |
332 | |
333 | // The destroy() function MUST be used to delete a Database object. |
334 | // The function hides some tricky order of operations. Since the |
335 | // memory for the vectors in the Database is allocated out of the Database's |
336 | // permanent memory pool, the entire delete() operation needs |
337 | // to complete _before_ the permanent pool is deleted, or else |
338 | // risk an aborted engine. |
339 | static void destroy(Database* const toDelete) |
340 | { |
341 | if (!toDelete) |
342 | return; |
343 | |
344 | MemoryPool* const perm = toDelete->dbb_permanent; |
345 | |
346 | // Memory pool destruction below decrements memory statistics |
347 | // situated in database block we are about to deallocate right now |
348 | Firebird::MemoryStats temp_stats; |
349 | perm->setStatsGroup(temp_stats); |
350 | |
351 | delete toDelete; |
352 | MemoryPool::deletePool(perm); |
353 | } |
354 | |
355 | static ULONG getLockOwnerId() |
356 | { |
357 | return fb_utils::genUniqueId(); |
358 | } |
359 | |
360 | Firebird::SyncObject dbb_sync; |
361 | Firebird::SyncObject dbb_sys_attach; // synchronize operations with dbb_sys_attachments |
362 | Firebird::SyncObject dbb_lck_sync; // synchronize operations with att_long_locks at different attachments |
363 | |
364 | MemoryPool* dbb_permanent; |
365 | |
366 | LockManager* dbb_lock_mgr; |
367 | EventManager* dbb_event_mgr; |
368 | |
369 | Database* dbb_next; // Next database block in system |
370 | Attachment* dbb_attachments; // Active attachments |
371 | Attachment* dbb_sys_attachments; // System attachments |
372 | BufferControl* dbb_bcb; // Buffer control block |
373 | int dbb_monitoring_id; // dbb monitoring identifier |
374 | Lock* dbb_lock; // database lock |
375 | Lock* dbb_sweep_lock; // sweep lock |
376 | |
377 | Firebird::SyncObject dbb_sh_counter_sync; |
378 | |
379 | Firebird::SyncObject dbb_shadow_sync; |
380 | Shadow* dbb_shadow; // shadow control block |
381 | Lock* dbb_shadow_lock; // lock for synchronizing addition of shadows |
382 | |
383 | Lock* dbb_retaining_lock; // lock for preserving commit retaining snapshot |
384 | Lock* dbb_monitor_lock; // lock for monitoring purposes |
385 | PageManager dbb_page_manager; |
386 | vcl* dbb_t_pages; // pages number for transactions |
387 | vcl* dbb_gen_id_pages; // known pages for gen_id |
388 | BlobFilter* dbb_blob_filters; // known blob filters |
389 | |
390 | Firebird::SyncObject dbb_mon_sync; // synchronize operations with dbb_monitor_lock |
391 | MonitoringData* dbb_monitoring_data; // monitoring data |
392 | |
393 | DatabaseModules dbb_modules; // external function/filter modules |
394 | ExtEngineManager dbb_extManager; // external engine manager |
395 | |
396 | Firebird::SyncObject dbb_flush_count_mutex; |
397 | Firebird::RWLock dbb_ast_lock; // avoids delivering AST to going away database |
398 | Firebird::AtomicCounter dbb_ast_flags; // flags modified at AST level |
399 | Firebird::AtomicCounter dbb_flags; |
400 | USHORT dbb_ods_version; // major ODS version number |
401 | USHORT dbb_minor_version; // minor ODS version number |
402 | USHORT dbb_page_size; // page size |
403 | USHORT dbb_dp_per_pp; // data pages per pointer page |
404 | USHORT dbb_max_records; // max record per data page |
405 | USHORT dbb_max_idx; // max number of indexes on a root page |
406 | |
407 | #ifdef SUPERSERVER_V2 |
408 | USHORT dbb_prefetch_sequence; // sequence to pace frequency of prefetch requests |
409 | USHORT dbb_prefetch_pages; // prefetch pages per request |
410 | #endif |
411 | |
412 | Firebird::PathName dbb_filename; // filename string |
413 | Firebird::PathName dbb_database_name; // database ID (file name or alias) |
414 | |
415 | Firebird::MetaName dbb_owner; // database owner |
416 | |
417 | Firebird::SyncObject dbb_pools_sync; |
418 | Firebird::Array<MemoryPool*> dbb_pools; // pools |
419 | |
420 | Firebird::SyncObject dbb_sortbuf_sync; |
421 | Firebird::Array<UCHAR*> dbb_sort_buffers; // sort buffers ready for reuse |
422 | |
423 | Firebird::SyncObject dbb_threads_sync; |
424 | thread_db* dbb_active_threads; |
425 | |
426 | TraNumber dbb_oldest_active; // Cached "oldest active" transaction |
427 | TraNumber dbb_oldest_transaction; // Cached "oldest interesting" transaction |
428 | TraNumber dbb_oldest_snapshot; // Cached "oldest snapshot" of all active transactions |
429 | TraNumber dbb_next_transaction; // Next transaction id used by NETWARE |
430 | SLONG dbb_attachment_id; // Next attachment id for ReadOnly DB's |
431 | ULONG dbb_page_buffers; // Page buffers from header page |
432 | |
433 | GarbageCollector* dbb_garbage_collector; // GarbageCollector class |
434 | Firebird::Semaphore dbb_gc_sem; // Event to wake up garbage collector |
435 | Firebird::Semaphore dbb_gc_init; // Event for initialization garbage collector |
436 | Firebird::Semaphore dbb_gc_fini; // Event for finalization garbage collector |
437 | |
438 | Firebird::MemoryStats dbb_memory_stats; |
439 | |
440 | RuntimeStatistics dbb_stats; |
441 | TraNumber ; // Transaction id of last header page physical write |
442 | SLONG dbb_flush_cycle; // Current flush cycle |
443 | ULONG dbb_sweep_interval; // Transactions between sweep |
444 | const ULONG dbb_lock_owner_id; // ID for the lock manager |
445 | SLONG dbb_lock_owner_handle; // Handle for the lock manager |
446 | |
447 | USHORT unflushed_writes; // unflushed writes |
448 | time_t last_flushed_write; // last flushed write time |
449 | |
450 | TipCache* dbb_tip_cache; // cache of latest known state of all transactions in system |
451 | TransactionsVector* dbb_pc_transactions; // active precommitted transactions |
452 | BackupManager* dbb_backup_manager; // physical backup manager |
453 | Firebird::TimeStamp dbb_creation_date; // creation date |
454 | ExternalFileDirectoryList* dbb_external_file_directory_list; |
455 | Firebird::RefPtr<Config> dbb_config; |
456 | |
457 | SharedCounter dbb_shared_counter; |
458 | CryptoManager* dbb_crypto_manager; |
459 | Firebird::RefPtr<ExistenceRefMutex> dbb_init_fini; |
460 | Firebird::RefPtr<Linger> dbb_linger_timer; |
461 | unsigned dbb_linger_seconds; |
462 | time_t dbb_linger_end; |
463 | Firebird::RefPtr<Firebird::IPluginConfig> dbb_plugin_config; |
464 | |
465 | // returns true if primary file is located on raw device |
466 | bool onRawDevice() const; |
467 | |
468 | // returns an unique ID string for a database file |
469 | Firebird::string getUniqueFileId() const; |
470 | |
471 | #ifdef DEV_BUILD |
472 | // returns true if main lock is in exclusive state |
473 | bool locked() const |
474 | { |
475 | return dbb_sync.ourExclusiveLock(); |
476 | } |
477 | #endif |
478 | |
479 | MemoryPool* createPool() |
480 | { |
481 | MemoryPool* const pool = MemoryPool::createPool(dbb_permanent, dbb_memory_stats); |
482 | |
483 | Firebird::SyncLockGuard guard(&dbb_pools_sync, Firebird::SYNC_EXCLUSIVE, "Database::createPool" ); |
484 | dbb_pools.add(pool); |
485 | return pool; |
486 | } |
487 | |
488 | void deletePool(MemoryPool* pool); |
489 | |
490 | private: |
491 | Database(MemoryPool* p, Firebird::IPluginConfig* pConf) |
492 | : dbb_permanent(p), |
493 | dbb_page_manager(this, *p), |
494 | dbb_modules(*p), |
495 | dbb_extManager(*p), |
496 | dbb_filename(*p), |
497 | dbb_database_name(*p), |
498 | dbb_pools(*p, 4), |
499 | dbb_sort_buffers(*p), |
500 | dbb_stats(*p), |
501 | dbb_lock_owner_id(getLockOwnerId()), |
502 | dbb_tip_cache(NULL), |
503 | dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()), |
504 | dbb_external_file_directory_list(NULL), |
505 | dbb_init_fini(FB_NEW(*getDefaultMemoryPool()) ExistenceRefMutex()), |
506 | dbb_linger_seconds(0), |
507 | dbb_linger_end(0), |
508 | dbb_plugin_config(pConf) |
509 | { |
510 | dbb_pools.add(p); |
511 | } |
512 | |
513 | ~Database(); |
514 | |
515 | public: |
516 | SLONG generateAttachmentId(thread_db* tdbb) |
517 | { |
518 | return dbb_shared_counter.generate(tdbb, SharedCounter::ATTACHMENT_ID_SPACE, 1); |
519 | } |
520 | |
521 | SLONG generateTransactionId(thread_db* tdbb) |
522 | { |
523 | return dbb_shared_counter.generate(tdbb, SharedCounter::TRANSACTION_ID_SPACE, 1); |
524 | } |
525 | |
526 | SLONG generateStatementId(thread_db* tdbb) |
527 | { |
528 | return dbb_shared_counter.generate(tdbb, SharedCounter::STATEMENT_ID_SPACE); |
529 | } |
530 | |
531 | USHORT getMaxIndexKeyLength() const |
532 | { |
533 | return dbb_page_size / 4; |
534 | } |
535 | |
536 | bool readOnly() const |
537 | { |
538 | return (dbb_flags & DBB_read_only) != 0; |
539 | } |
540 | |
541 | // returns true if sweeper thread could start |
542 | bool allowSweepThread(thread_db* tdbb); |
543 | // returns true if sweep could run |
544 | bool allowSweepRun(thread_db* tdbb); |
545 | // reset sweep flags and release sweep lock |
546 | void clearSweepFlags(thread_db* tdbb); |
547 | |
548 | private: |
549 | //static int blockingAstSharedCounter(void*); |
550 | static int blocking_ast_sweep(void* ast_object); |
551 | Lock* createSweepLock(thread_db* tdbb); |
552 | |
553 | // The delete operators are no-oped because the Database memory is allocated from the |
554 | // Database's own permanent pool. That pool has already been released by the Database |
555 | // destructor, so the memory has already been released. Hence the operator |
556 | // delete no-op. |
557 | void operator delete(void*) {} |
558 | void operator delete[](void*) {} |
559 | |
560 | Database(const Database&); // no impl. |
561 | const Database& operator =(const Database&) { return *this; } |
562 | }; |
563 | |
564 | } // namespace Jrd |
565 | |
566 | #endif // JRD_DATABASE_H |
567 | |