/* * PROGRAM: JRD access method * MODULE: Attachment.h * DESCRIPTION: JRD Attachment class * * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy * of the License at http://www.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * All Rights Reserved. * Contributor(s): ______________________________________. * */ #ifndef JRD_ATTACHMENT_H #define JRD_ATTACHMENT_H #include "firebird.h" // Definition of block types for data allocation in JRD #include "../include/fb_blk.h" #include "../jrd/scl.h" #include "../jrd/PreparedStatement.h" #include "../jrd/RandomGenerator.h" #include "../jrd/RuntimeStatistics.h" #include "../common/classes/ByteChunk.h" #include "../common/classes/GenericMap.h" #include "../common/classes/SyncObject.h" #include "../common/classes/array.h" #include "../common/classes/stack.h" #include "../common/classes/timestamp.h" #include "../common/ThreadStart.h" #include "../jrd/EngineInterface.h" namespace EDS { class Connection; } class CharSetContainer; namespace Jrd { class thread_db; class Database; class jrd_tra; class jrd_req; class Lock; class jrd_file; class Format; class BufferControl; class SparseBitmap; class jrd_rel; class ExternalFile; class ViewContext; class IndexBlock; class IndexLock; class ArrayField; struct sort_context; class vcl; class TextType; class Parameter; class jrd_fld; class dsql_dbb; class PreparedStatement; class TraceManager; template class vec; class jrd_rel; class jrd_prc; class Trigger; class TrigVector; class Function; class JrdStatement; class Validation; struct DSqlCacheItem { Lock* lock; bool locked; bool obsolete; }; typedef Firebird::GenericMap > > DSqlCache; struct DdlTriggerContext { DdlTriggerContext() : eventType(*getDefaultMemoryPool()), objectType(*getDefaultMemoryPool()), objectName(*getDefaultMemoryPool()), oldObjectName(*getDefaultMemoryPool()), newObjectName(*getDefaultMemoryPool()), sqlText(*getDefaultMemoryPool()) { } Firebird::string eventType; Firebird::string objectType; Firebird::MetaName objectName; Firebird::MetaName oldObjectName; Firebird::MetaName newObjectName; Firebird::string sqlText; }; // Attachment flags const ULONG ATT_no_cleanup = 0x00001L; // Don't expunge, purge, or garbage collect const ULONG ATT_shutdown = 0x00002L; // attachment has been shutdown const ULONG ATT_shutdown_manager = 0x00004L; // attachment requesting shutdown const ULONG ATT_exclusive = 0x00008L; // attachment wants exclusive database access const ULONG ATT_attach_pending = 0x00010L; // Indicate attachment is only pending const ULONG ATT_exclusive_pending = 0x00020L; // Indicate exclusive attachment pending const ULONG ATT_notify_gc = 0x00040L; // Notify garbage collector to expunge, purge .. const ULONG ATT_garbage_collector = 0x00080L; // I'm a garbage collector const ULONG ATT_cancel_raise = 0x00100L; // Cancel currently running operation const ULONG ATT_cancel_disable = 0x00200L; // Disable cancel operations const ULONG ATT_no_db_triggers = 0x00400L; // Don't execute database triggers const ULONG ATT_manual_lock = 0x00800L; // Was locked manually const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually //const ULONG ATT_purge_started = 0x02000L; // Purge already started - avoid 2 purges at once const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB const ULONG ATT_system = 0x04000L; // Special system attachment const ULONG ATT_creator = 0x08000L; // This attachment created the DB const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block const ULONG ATT_crypt_thread = 0x80000L; // Attachment from crypt thread const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); class Attachment; struct bid; // // RefCounted part of Attachment object, placed into permanent pool // class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage { public: explicit StableAttachmentPart(Attachment* handle) : att(handle), jAtt(NULL), shutError(0) { } Attachment* getHandle() throw() { return att; } JAttachment* getInterface() { return jAtt; } void setInterface(JAttachment* ja) { if (jAtt) jAtt->detachEngine(); jAtt = ja; shutError = 0; } Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false) { if (useAsync && !forceAsync) { fb_assert(!mainMutex.locked()); } return useAsync ? &asyncMutex : &mainMutex; } Firebird::Mutex* getBlockingMutex() { return &blockingMutex; } void cancel() { fb_assert(asyncMutex.locked()); fb_assert(mainMutex.locked()); att = NULL; } jrd_tra* getEngineTransaction(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* tra) { return getInterface()->getEngineTransaction(status, tra); } JTransaction* getTransactionInterface(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* tra) { return getInterface()->getTransactionInterface(status, tra); } void manualLock(ULONG& flags, const ULONG whatLock = ATT_manual_lock | ATT_async_manual_lock); void manualUnlock(ULONG& flags); void manualAsyncUnlock(ULONG& flags); void setShutError(ISC_STATUS code) { if (!shutError) shutError = code; } ISC_STATUS getShutError() const { return shutError; } private: Attachment* att; JAttachment* jAtt; ISC_STATUS shutError; // These mutexes guarantee attachment existence. After releasing both of them with possibly // zero att_use_count one should check does attachment still exists calling getHandle(). Firebird::Mutex mainMutex, asyncMutex; // This mutex guarantees attachment is not accessed by more than single external thread. Firebird::Mutex blockingMutex; }; // // the attachment block; one is created for each attachment to a database // class Attachment : public pool_alloc { public: class SyncGuard { public: SyncGuard(StableAttachmentPart* js, const char* f, bool optional = false) : jStable(js) { init(f, optional); } SyncGuard(Attachment* att, const char* f, bool optional = false) : jStable(att ? att->getStable() : NULL) { init(f, optional); } ~SyncGuard() { if (jStable) jStable->getMutex()->leave(); } private: // copying is prohibited SyncGuard(const SyncGuard&); SyncGuard& operator=(const SyncGuard&); void init(const char* f, bool optional); Firebird::RefPtr jStable; }; public: static Attachment* create(Database* dbb); static void destroy(Attachment* const attachment); MemoryPool* const att_pool; // Memory pool Firebird::MemoryStats att_memory_stats; Database* att_database; // Parent database block Attachment* att_next; // Next attachment to database UserId* att_user; // User identification jrd_tra* att_transactions; // Transactions belonging to attachment jrd_tra* att_dbkey_trans; // transaction to control db-key scope TraNumber att_oldest_snapshot; // GTT's record versions older than this can be garbage-collected private: jrd_tra* att_sys_transaction; // system transaction StableAttachmentPart* att_stable; public: Firebird::SortedArray att_requests; // Requests belonging to attachment Lock* att_id_lock; // Attachment lock (if any) AttNumber att_attachment_id; // Attachment ID Lock* att_cancel_lock; // Lock to cancel the active request Lock* att_monitor_lock; // Lock for monitoring purposes const ULONG att_lock_owner_id; // ID for the lock manager SLONG att_lock_owner_handle; // Handle for the lock manager ULONG att_backup_state_counter; // Counter of backup state locks for attachment SLONG att_event_session; // Event session id, if any SecurityClass* att_security_class; // security class for database SecurityClassList* att_security_classes; // security classes RuntimeStatistics att_stats; RuntimeStatistics att_base_stats; ULONG att_flags; // Flags describing the state of the attachment SSHORT att_client_charset; // user's charset specified in dpb SSHORT att_charset; // current (client or external) attachment charset Lock* att_long_locks; // outstanding two phased locks Lock* att_wait_lock; // lock at which attachment waits currently vec* att_compatibility_table; // hash table of compatible locks Validation* att_validation; Firebird::PathName att_working_directory; // Current working directory is cached Firebird::PathName att_filename; // alias used to attach the database const Firebird::TimeStamp att_timestamp; // Connection date and time Firebird::StringMap att_context_vars; // Context variables for the connection Firebird::Stack ddlTriggersContext; // Context variables for DDL trigger event Firebird::string att_network_protocol; // Network protocol used by client for connection Firebird::string att_remote_address; // Protocol-specific address of remote client SLONG att_remote_pid; // Process id of remote client Firebird::PathName att_remote_process; // Process name of remote client Firebird::string att_client_version; // Version of the client library Firebird::string att_remote_protocol; // Details about the remote protocol Firebird::string att_remote_host; // Host name of remote client Firebird::string att_remote_os_user; // OS user name of remote client RandomGenerator att_random_generator; // Random bytes generator Lock* att_temp_pg_lock; // temporary pagespace ID lock DSqlCache att_dsql_cache; // DSQL cache locks Firebird::SortedArray att_udf_pointers; dsql_dbb* att_dsql_instance; bool att_in_use; // attachment in use (can't be detached or dropped) int att_use_count; // number of API calls running except of asynchronous ones ThreadId att_purge_tid; // ID of thread running purge_attachment() EDS::Connection* att_ext_connection; // external connection executed by this attachment ULONG att_ext_call_depth; // external connection call depth, 0 for user attachment TraceManager* att_trace_manager; // Trace API manager enum UtilType { UTIL_NONE, UTIL_GBAK, UTIL_GFIX, UTIL_GSTAT }; UtilType att_utility; /// former Database members - start vec* att_relations; // relation vector Firebird::Array att_procedures; // scanned procedures TrigVector* att_triggers[DB_TRIGGER_MAX]; TrigVector* att_ddl_triggers; Firebird::Array att_functions; // User defined functions Firebird::Array att_internal; // internal statements Firebird::Array att_dyn_req; // internal dyn statements Firebird::ICryptKeyCallback* att_crypt_callback; // callback for DB crypt Firebird::DecimalStatus att_dec_status; // error handling and rounding Firebird::DecimalBinding att_dec_binding; // use legacy datatype for DecFloat in outer world jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which); Firebird::Array att_charsets; // intl character set descriptions Firebird::GenericMap > > att_charset_ids; // Character set ids void releaseIntlObjects(thread_db* tdbb); // defined in intl.cpp void destroyIntlObjects(thread_db* tdbb); // defined in intl.cpp void initLocks(thread_db* tdbb); void releaseLocks(thread_db* tdbb); void detachLocks(); void releaseRelations(thread_db* tdbb); static int blockingAstShutdown(void*); static int blockingAstCancel(void*); static int blockingAstMonitor(void*); Firebird::Array att_pools; // pools MemoryPool* createPool(); void deletePool(MemoryPool* pool); /// former Database members - end bool locksmith(thread_db* tdbb, SystemPrivilege sp) const; jrd_tra* getSysTransaction(); void setSysTransaction(jrd_tra* trans); // used only by TRA_init bool isGbak() const; bool isRWGbak() const; bool isUtility() const; // gbak, gfix and gstat. PreparedStatement* prepareStatement(thread_db* tdbb, jrd_tra* transaction, const Firebird::string& text, Firebird::MemoryPool* pool = NULL); PreparedStatement* prepareStatement(thread_db* tdbb, jrd_tra* transaction, const PreparedStatement::Builder& builder, Firebird::MemoryPool* pool = NULL); PreparedStatement* prepareUserStatement(thread_db* tdbb, jrd_tra* transaction, const Firebird::string& text, Firebird::MemoryPool* pool = NULL); Firebird::MetaName nameToMetaCharSet(thread_db* tdbb, const Firebird::MetaName& name); Firebird::MetaName nameToUserCharSet(thread_db* tdbb, const Firebird::MetaName& name); Firebird::string stringToMetaCharSet(thread_db* tdbb, const Firebird::string& str, const char* charSet = NULL); Firebird::string stringToUserCharSet(thread_db* tdbb, const Firebird::string& str); void storeMetaDataBlob(thread_db* tdbb, jrd_tra* transaction, bid* blobId, const Firebird::string& text, USHORT fromCharSet = CS_METADATA); void storeBinaryBlob(thread_db* tdbb, jrd_tra* transaction, bid* blobId, const Firebird::ByteChunk& chunk); void signalCancel(); void signalShutdown(ISC_STATUS code); void mergeStats(); bool backupStateWriteLock(thread_db* tdbb, SSHORT wait); void backupStateWriteUnLock(thread_db* tdbb); bool backupStateReadLock(thread_db* tdbb, SSHORT wait); void backupStateReadUnLock(thread_db* tdbb); StableAttachmentPart* getStable() throw() { return att_stable; } void setStable(StableAttachmentPart *js) throw() { att_stable = js; } JAttachment* getInterface() throw(); unsigned int getIdleTimeout() const { return att_idle_timeout; } void setIdleTimeout(unsigned int timeOut) { att_idle_timeout = timeOut; } unsigned int getActualIdleTimeout() const; unsigned int getStatementTimeout() const { return att_stmt_timeout; } void setStatementTimeout(unsigned int timeOut) { att_stmt_timeout = timeOut; } // evaluate new value or clear idle timer void setupIdleTimer(bool clear); // returns time when idle timer will be expired, if set bool getIdleTimerTimestamp(Firebird::TimeStamp& ts) const; private: Attachment(MemoryPool* pool, Database* dbb); ~Attachment(); class IdleTimer FB_FINAL : public Firebird::RefCntIface > { public: explicit IdleTimer(JAttachment* jAtt) : m_attachment(jAtt), m_fireTime(0), m_expTime(0) { } // ITimer implementation void handler(); int release(); // Set timeout, seconds void reset(unsigned int timeout); time_t getExpiryTime() const { return m_expTime; } private: Firebird::RefPtr m_attachment; time_t m_fireTime; // when ITimer will fire, could be less than m_expTime time_t m_expTime; // when actual idle timeout will expire }; unsigned int att_idle_timeout; // seconds unsigned int att_stmt_timeout; // milliseconds Firebird::RefPtr att_idle_timer; }; inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const { return att_user && att_user->locksmith(tdbb, sp); } inline jrd_tra* Attachment::getSysTransaction() { return att_sys_transaction; } inline void Attachment::setSysTransaction(jrd_tra* trans) { att_sys_transaction = trans; } // Connection is from GBAK inline bool Attachment::isGbak() const { return (att_utility == UTIL_GBAK); } // Gbak changes objects when it's restoring (creating) a db. // Other attempts are fake. Gbak reconnects to change R/O status and other db-wide settings, // but it doesn't modify generators or tables that seconds time. inline bool Attachment::isRWGbak() const { return (isGbak() && (att_flags & ATT_creator)); } // Any of the three original utilities: gbak, gfix or gstat. inline bool Attachment::isUtility() const { return (att_utility != UTIL_NONE); } // This class holds references to all attachments it contains class AttachmentsRefHolder { friend class Iterator; public: class Iterator { public: explicit Iterator(AttachmentsRefHolder& list) : m_list(list), m_index(0) {} StableAttachmentPart* operator*() { if (m_index < m_list.m_attachments.getCount()) return m_list.m_attachments[m_index]; return NULL; } void operator++() { m_index++; } void remove() { if (m_index < m_list.m_attachments.getCount()) { AttachmentsRefHolder::debugHelper(FB_FUNCTION); m_list.m_attachments[m_index]->release(); m_list.m_attachments.remove(m_index); } } private: // copying is prohibited Iterator(const Iterator&); Iterator& operator=(const Iterator&); AttachmentsRefHolder& m_list; FB_SIZE_T m_index; }; explicit AttachmentsRefHolder(MemoryPool& p) : m_attachments(p) {} AttachmentsRefHolder& operator=(const AttachmentsRefHolder& other) { this->~AttachmentsRefHolder(); for (FB_SIZE_T i = 0; i < other.m_attachments.getCount(); i++) add(other.m_attachments[i]); return *this; } ~AttachmentsRefHolder() { while (m_attachments.hasData()) { debugHelper(FB_FUNCTION); m_attachments.pop()->release(); } } void add(StableAttachmentPart* jAtt) { if (jAtt) { jAtt->addRef(); m_attachments.add(jAtt); } } void remove(Iterator& iter) { iter.remove(); } private: AttachmentsRefHolder(const AttachmentsRefHolder&); static void debugHelper(const char* from); Firebird::HalfStaticArray m_attachments; }; // Class used in system background threads class SysStableAttachment : public StableAttachmentPart { public: explicit SysStableAttachment(Attachment* handle); void initDone(); virtual ~SysStableAttachment() { Attachment* attachment = getHandle(); if (attachment) { destroy(attachment); } } private: void destroy(Attachment* attachment); // "public" interface for internal (system) attachment Firebird::RefPtr m_JAttachment; }; } // namespace Jrd #endif // JRD_ATTACHMENT_H