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
68namespace Jrd
69{
70template <typename T> class vec;
71class jrd_rel;
72class Shadow;
73class BlobFilter;
74class TipCache;
75class BackupManager;
76class ExternalFileDirectoryList;
77class MonitoringData;
78class GarbageCollector;
79class CryptoManager;
80
81// general purpose vector
82template <class T, BlockType TYPE = type_vec>
83class vec_base : protected pool_alloc<TYPE>
84{
85public:
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
119protected:
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
132private:
133 Firebird::Array<T> v;
134};
135
136template <typename T>
137class vec : public vec_base<T, type_vec>
138{
139public:
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
159private:
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
164class vcl : public vec_base<ULONG, type_vcl>
165{
166public:
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
186private:
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
191typedef vec<TraNumber> TransactionsVector;
192
193
194//
195// bit values for dbb_flags
196//
197const ULONG DBB_damaged = 0x1L;
198const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode
199const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred
200const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists
201const ULONG DBB_gc_active = 0x10L; // ... and is actively working.
202const ULONG DBB_gc_pending = 0x20L; // garbage collection requested
203const ULONG DBB_force_write = 0x40L; // Database is forced write
204const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions
205const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3
206const ULONG DBB_read_only = 0x200L; // DB is ReadOnly (RO). If not set, DB is RW
207const ULONG DBB_being_opened_read_only = 0x400L; // DB is being opened RO. If unset, opened as RW
208const ULONG DBB_no_ast = 0x800L; // AST delivery is prohibited
209const ULONG DBB_sweep_in_progress = 0x1000L; // A database sweep operation is in progress
210const ULONG DBB_security_db = 0x2000L; // ISC security database
211const ULONG DBB_suspend_bgio = 0x4000L; // Suspend I/O by background threads
212const ULONG DBB_new = 0x8000L; // Database object is just created
213const ULONG DBB_gc_cooperative = 0x10000L; // cooperative garbage collection
214const ULONG DBB_gc_background = 0x20000L; // background garbage collection by gc_thread
215const ULONG DBB_no_fs_cache = 0x40000L; // Not using file system cache
216const ULONG DBB_sweep_starting = 0x80000L; // Auto-sweep is starting
217const ULONG DBB_creating = 0x100000L; // Database creation is in progress
218
219//
220// dbb_ast_flags
221//
222const ULONG DBB_blocking = 0x1L; // Exclusive mode is blocking
223const ULONG DBB_get_shadows = 0x2L; // Signal received to check for new shadows
224const ULONG DBB_assert_locks = 0x4L; // Locks are to be asserted
225const ULONG DBB_shutdown = 0x8L; // Database is shutdown
226const ULONG DBB_shut_attach = 0x10L; // no new attachments accepted
227const ULONG DBB_shut_tran = 0x20L; // no new transactions accepted
228const ULONG DBB_shut_force = 0x40L; // forced shutdown in progress
229const ULONG DBB_shutdown_full = 0x80L; // Database fully shut down
230const ULONG DBB_shutdown_single = 0x100L; // Database is in single-user maintenance mode
231const ULONG DBB_monitor_off = 0x200L; // Database has the monitoring lock released
232
233class Database : public pool_alloc<type_dbb>
234{
235public:
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 dbb_last_header_write; // 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
490private:
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
515public:
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
548private:
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