mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-26 10:43:03 +01:00
1002 lines
26 KiB
C++
1002 lines
26 KiB
C++
/*
|
|
* PROGRAM: JRD access method
|
|
* MODULE: jrd.h
|
|
* DESCRIPTION: Common descriptions
|
|
*
|
|
* 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): ______________________________________.
|
|
*
|
|
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
|
|
*
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
* Claudio Valderrama C.
|
|
* Adriano dos Santos Fernandes
|
|
*
|
|
*/
|
|
|
|
#ifndef JRD_JRD_H
|
|
#define JRD_JRD_H
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
#include "../jrd/common.h"
|
|
#include "../jrd/dsc.h"
|
|
#include "../jrd/all.h"
|
|
#include "../jrd/btn.h"
|
|
#include "../jrd/all.h"
|
|
#include "../jrd/jrd_proto.h"
|
|
#include "../jrd/val.h"
|
|
|
|
#include "../common/classes/fb_atomic.h"
|
|
#include "../common/classes/fb_string.h"
|
|
#include "../common/classes/MetaName.h"
|
|
#include "../common/classes/array.h"
|
|
#include "../common/classes/objects_array.h"
|
|
#include "../common/classes/stack.h"
|
|
#include "../common/classes/timestamp.h"
|
|
#include "../common/classes/GenericMap.h"
|
|
#include "../common/utils_proto.h"
|
|
#include "../jrd/RandomGenerator.h"
|
|
#include "../jrd/os/guid.h"
|
|
#include "../jrd/sbm.h"
|
|
#include "../jrd/scl.h"
|
|
|
|
#ifdef DEV_BUILD
|
|
#define DEBUG if (debug) DBG_supervisor(debug);
|
|
//#define VIO_DEBUG // remove this for production build
|
|
#else // PROD
|
|
#define DEBUG
|
|
#undef VIO_DEBUG
|
|
#endif
|
|
|
|
#define BUGCHECK(number) ERR_bugcheck (number, __FILE__, __LINE__)
|
|
#define CORRUPT(number) ERR_corrupt (number)
|
|
#define IBERROR(number) ERR_error (number)
|
|
|
|
|
|
#define BLKCHK(blk, type) if (!blk->checkHandle()) BUGCHECK(147)
|
|
|
|
#define DEV_BLKCHK(blk, type) // nothing
|
|
|
|
|
|
// Thread data block / IPC related data blocks
|
|
#include "../jrd/ThreadData.h"
|
|
|
|
// recursive mutexes
|
|
#include "../common/thd.h"
|
|
|
|
// Definition of block types for data allocation in JRD
|
|
#include "../include/fb_blk.h"
|
|
|
|
#include "../jrd/blb.h"
|
|
|
|
// Definition of DatabasePlugins
|
|
#include "../jrd/flu.h"
|
|
|
|
#include "../jrd/pag.h"
|
|
|
|
#include "../jrd/RuntimeStatistics.h"
|
|
#include "../jrd/Database.h"
|
|
|
|
// Error codes
|
|
#include "../include/gen/iberror.h"
|
|
|
|
namespace Firebird {
|
|
class StringsBuffer;
|
|
}
|
|
|
|
class str;
|
|
struct dsc;
|
|
struct thread;
|
|
struct mod;
|
|
|
|
namespace EDS {
|
|
class Connection;
|
|
}
|
|
|
|
namespace Jrd {
|
|
|
|
const int QUANTUM = 100; // Default quantum
|
|
const int SWEEP_QUANTUM = 10; // Make sweeps less disruptive
|
|
|
|
// fwd. decl.
|
|
class thread_db;
|
|
class Attachment;
|
|
class jrd_tra;
|
|
class jrd_req;
|
|
class Lock;
|
|
class jrd_file;
|
|
class Format;
|
|
class jrd_nod;
|
|
class BufferControl;
|
|
class SparseBitmap;
|
|
class jrd_rel;
|
|
class ExternalFile;
|
|
class ViewContext;
|
|
class IndexBlock;
|
|
class IndexLock;
|
|
class ArrayField;
|
|
class Symbol;
|
|
struct sort_context;
|
|
class RecordSelExpr;
|
|
class vcl;
|
|
class TextType;
|
|
class Parameter;
|
|
class jrd_fld;
|
|
class dsql_dbb;
|
|
class PreparedStatement;
|
|
class TraceManager;
|
|
|
|
// The database block, the topmost block in the metadata
|
|
// cache for a database
|
|
|
|
// Relation trigger definition
|
|
|
|
class Trigger
|
|
{
|
|
public:
|
|
Firebird::HalfStaticArray<UCHAR, 128> blr; // BLR code
|
|
bid dbg_blob_id; // RDB$DEBUG_INFO
|
|
jrd_req* request; // Compiled request. Gets filled on first invocation
|
|
bool compile_in_progress;
|
|
bool sys_trigger;
|
|
UCHAR type; // Trigger type
|
|
USHORT flags; // Flags as they are in RDB$TRIGGERS table
|
|
jrd_rel* relation; // Trigger parent relation
|
|
Firebird::MetaName name; // Trigger name
|
|
void compile(thread_db*); // Ensure that trigger is compiled
|
|
void release(thread_db*); // Try to free trigger request
|
|
|
|
explicit Trigger(MemoryPool& p)
|
|
: blr(p), name(p)
|
|
{
|
|
dbg_blob_id.clear();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Database attachments
|
|
//
|
|
const int DBB_read_seq_count = 0;
|
|
const int DBB_read_idx_count = 1;
|
|
const int DBB_update_count = 2;
|
|
const int DBB_insert_count = 3;
|
|
const int DBB_delete_count = 4;
|
|
const int DBB_backout_count = 5;
|
|
const int DBB_purge_count = 6;
|
|
const int DBB_expunge_count = 7;
|
|
const int DBB_max_count = 8;
|
|
|
|
//
|
|
// Flags to indicate normal internal requests vs. dyn internal requests
|
|
//
|
|
const int IRQ_REQUESTS = 1;
|
|
const int DYN_REQUESTS = 2;
|
|
|
|
|
|
//
|
|
// Errors during validation - will be returned on info calls
|
|
// CVC: It seems they will be better in a header for val.cpp that's not val.h
|
|
//
|
|
const int VAL_PAG_WRONG_TYPE = 0;
|
|
const int VAL_PAG_CHECKSUM_ERR = 1;
|
|
const int VAL_PAG_DOUBLE_ALLOC = 2;
|
|
const int VAL_PAG_IN_USE = 3;
|
|
const int VAL_PAG_ORPHAN = 4;
|
|
const int VAL_BLOB_INCONSISTENT = 5;
|
|
const int VAL_BLOB_CORRUPT = 6;
|
|
const int VAL_BLOB_TRUNCATED = 7;
|
|
const int VAL_REC_CHAIN_BROKEN = 8;
|
|
const int VAL_DATA_PAGE_CONFUSED = 9;
|
|
const int VAL_DATA_PAGE_LINE_ERR = 10;
|
|
const int VAL_INDEX_PAGE_CORRUPT = 11;
|
|
const int VAL_P_PAGE_LOST = 12;
|
|
const int VAL_P_PAGE_INCONSISTENT = 13;
|
|
const int VAL_REC_DAMAGED = 14;
|
|
const int VAL_REC_BAD_TID = 15;
|
|
const int VAL_REC_FRAGMENT_CORRUPT = 16;
|
|
const int VAL_REC_WRONG_LENGTH = 17;
|
|
const int VAL_INDEX_ROOT_MISSING = 18;
|
|
const int VAL_TIP_LOST = 19;
|
|
const int VAL_TIP_LOST_SEQUENCE = 20;
|
|
const int VAL_TIP_CONFUSED = 21;
|
|
const int VAL_REL_CHAIN_ORPHANS = 22;
|
|
const int VAL_INDEX_MISSING_ROWS = 23;
|
|
const int VAL_INDEX_ORPHAN_CHILD = 24;
|
|
const int VAL_INDEX_CYCLE = 25;
|
|
const int VAL_MAX_ERROR = 26;
|
|
|
|
|
|
struct DSqlCacheItem
|
|
{
|
|
Lock* lock;
|
|
bool locked;
|
|
bool obsolete;
|
|
};
|
|
|
|
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<
|
|
Firebird::string, DSqlCacheItem> > > DSqlCache;
|
|
|
|
|
|
//
|
|
// the attachment block; one is created for each attachment to a database
|
|
//
|
|
class Attachment : public pool_alloc<type_att>
|
|
{
|
|
public:
|
|
static Attachment* create(Database* dbb)
|
|
{
|
|
MemoryPool* const pool = dbb->createPool();
|
|
|
|
try
|
|
{
|
|
Attachment* const attachment = FB_NEW(*pool) Attachment(pool, dbb);
|
|
pool->setStatsGroup(attachment->att_memory_stats);
|
|
return attachment;
|
|
}
|
|
catch (const Firebird::Exception&)
|
|
{
|
|
dbb->deletePool(pool);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
static void destroy(Attachment* const attachment)
|
|
{
|
|
if (attachment)
|
|
{
|
|
Database* const dbb = attachment->att_database;
|
|
MemoryPool* const pool = attachment->att_pool;
|
|
Firebird::MemoryStats temp_stats;
|
|
pool->setStatsGroup(temp_stats);
|
|
delete attachment;
|
|
dbb->deletePool(pool);
|
|
}
|
|
}
|
|
|
|
/* Attachment()
|
|
: att_database(0),
|
|
att_next(0),
|
|
att_blocking(0),
|
|
att_user(0),
|
|
att_transactions(0),
|
|
att_dbkey_trans(0),
|
|
att_requests(0),
|
|
att_active_sorts(0),
|
|
att_id_lock(0),
|
|
att_attachment_id(0),
|
|
att_lock_owner_handle(0),
|
|
att_event_session(0),
|
|
att_security_class(0),
|
|
att_security_classes(0),
|
|
att_flags(0),
|
|
att_charset(0),
|
|
att_lc_messages(0),
|
|
att_long_locks(0),
|
|
att_compatibility_table(0),
|
|
att_val_errors(0),
|
|
att_working_directory(0)
|
|
{
|
|
att_counts[0] = 0;
|
|
}*/
|
|
|
|
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
|
|
jrd_req* att_requests; // Requests belonging to attachment
|
|
sort_context* att_active_sorts; // Active sorts
|
|
Lock* att_id_lock; // Attachment lock (if any)
|
|
SLONG att_attachment_id; // Attachment ID
|
|
const ULONG att_lock_owner_id; // ID for the lock manager
|
|
SLONG att_lock_owner_handle; // Handle for the lock manager
|
|
SLONG att_event_session; // Event session id, if any
|
|
SecurityClass* att_security_class; // security class for database
|
|
SecurityClassList* att_security_classes; // security classes
|
|
vcl* att_counts[DBB_max_count];
|
|
RuntimeStatistics att_stats;
|
|
ULONG att_flags; // Flags describing the state of the attachment
|
|
SSHORT att_charset; // user's charset specified in dpb
|
|
// The following data member is set but never used, so the DPB to set the location of a
|
|
// customized firebird.msg file doesn't work; the only way is to use an env var.
|
|
Firebird::PathName att_lc_messages; // attachment's preference for message natural language
|
|
Lock* att_long_locks; // outstanding two phased locks
|
|
vec<Lock*>* att_compatibility_table; // hash table of compatible locks
|
|
vcl* att_val_errors;
|
|
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::string att_network_protocol; // Network protocol used by client for connection
|
|
Firebird::string att_remote_address; // Protocol-specific addess of remote client
|
|
SLONG att_remote_pid; // Process id of remote client
|
|
Firebird::PathName att_remote_process; // Process name of remote client
|
|
RandomGenerator att_random_generator; // Random bytes generator
|
|
#ifndef SUPERSERVER
|
|
Lock* att_temp_pg_lock; // temporary pagespace ID lock
|
|
#endif
|
|
DSqlCache att_dsql_cache; // DSQL cache locks
|
|
Firebird::SortedArray<void*> att_udf_pointers;
|
|
dsql_dbb* att_dsql_instance;
|
|
Firebird::Mutex att_mutex; // attachment mutex
|
|
|
|
Firebird::StringsBuffer* att_strings_buffer; // per attachment circular strings buffer
|
|
Firebird::Mutex att_strings_mutex; // mutex for this buffer access
|
|
|
|
EDS::Connection* att_ext_connection; // external connection executed by this attachment
|
|
TraceManager* att_trace_manager; // Trace API manager
|
|
|
|
bool locksmith() const;
|
|
|
|
PreparedStatement* prepareStatement(thread_db* tdbb, Firebird::MemoryPool& pool,
|
|
jrd_tra* transaction, const Firebird::string& text);
|
|
|
|
void cancelExternalConnection(thread_db* tdbb);
|
|
|
|
private:
|
|
Attachment(MemoryPool* pool, Database* dbb);
|
|
~Attachment();
|
|
};
|
|
|
|
|
|
// Attachment flags
|
|
|
|
const ULONG ATT_no_cleanup = 1; // Don't expunge, purge, or garbage collect
|
|
const ULONG ATT_shutdown = 2; // attachment has been shutdown
|
|
const ULONG ATT_purge_error = 4; // trouble happened in purge attachment, att_mutex remains locked
|
|
const ULONG ATT_shutdown_manager = 8; // attachment requesting shutdown
|
|
const ULONG ATT_lck_init_done = 16; // LCK_init() called for the attachment
|
|
const ULONG ATT_exclusive = 32; // attachment wants exclusive database access
|
|
const ULONG ATT_attach_pending = 64; // Indicate attachment is only pending
|
|
const ULONG ATT_exclusive_pending = 128; // Indicate exclusive attachment pending
|
|
const ULONG ATT_gbak_attachment = 256; // Indicate GBAK attachment
|
|
|
|
#ifdef GARBAGE_THREAD
|
|
const ULONG ATT_notify_gc = 1024; // Notify garbage collector to expunge, purge ..
|
|
const ULONG ATT_disable_notify_gc = 2048; // Temporarily perform own garbage collection
|
|
const ULONG ATT_garbage_collector = 4096; // I'm a garbage collector
|
|
|
|
const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc);
|
|
#else
|
|
const ULONG ATT_NO_CLEANUP = ATT_no_cleanup;
|
|
#endif
|
|
|
|
const ULONG ATT_cancel_raise = 8192; // Cancel currently running operation
|
|
const ULONG ATT_cancel_disable = 16384; // Disable cancel operations
|
|
const ULONG ATT_gfix_attachment = 32768; // Indicate a GFIX attachment
|
|
const ULONG ATT_gstat_attachment = 65536; // Indicate a GSTAT attachment
|
|
const ULONG ATT_no_db_triggers = 131072; // Don't execute database triggers
|
|
|
|
|
|
inline bool Attachment::locksmith() const
|
|
{
|
|
return att_user && att_user->locksmith();
|
|
}
|
|
|
|
|
|
|
|
// Procedure block
|
|
|
|
class jrd_prc : public pool_alloc<type_prc>
|
|
{
|
|
public:
|
|
USHORT prc_id;
|
|
USHORT prc_flags;
|
|
USHORT prc_inputs;
|
|
USHORT prc_defaults;
|
|
USHORT prc_outputs;
|
|
//jrd_nod* prc_input_msg; // It's set once by met.epp and never used.
|
|
jrd_nod* prc_output_msg;
|
|
Format* prc_input_fmt;
|
|
Format* prc_output_fmt;
|
|
Format* prc_format;
|
|
vec<Parameter*>* prc_input_fields; // vector of field blocks
|
|
vec<Parameter*>* prc_output_fields; // vector of field blocks
|
|
prc_t prc_type; // procedure type
|
|
jrd_req* prc_request; // compiled procedure request
|
|
USHORT prc_use_count; // requests compiled with procedure
|
|
SSHORT prc_int_use_count; // number of procedures compiled with procedure, set and
|
|
// used internally in the MET_clear_cache procedure
|
|
// no code should rely on value of this field
|
|
// (it will usually be 0)
|
|
Lock* prc_existence_lock; // existence lock, if any
|
|
Firebird::MetaName prc_security_name; // security class name for procedure
|
|
Firebird::MetaName prc_name; // ascic name
|
|
USHORT prc_alter_count; // No. of times the procedure was altered
|
|
|
|
public:
|
|
explicit jrd_prc(MemoryPool& p)
|
|
: prc_security_name(p), prc_name(p)
|
|
{}
|
|
};
|
|
|
|
// prc_flags
|
|
|
|
const USHORT PRC_scanned = 1; // Field expressions scanned
|
|
const USHORT PRC_system = 2; // Set in met.epp, never tested.
|
|
const USHORT PRC_obsolete = 4; // Procedure known gonzo
|
|
const USHORT PRC_being_scanned = 8; // New procedure needs dependencies during scan
|
|
//const USHORT PRC_blocking = 16; // Blocking someone from dropping procedure
|
|
const USHORT PRC_create = 32; // Newly created. Set in met.epp, never tested or disabled.
|
|
const USHORT PRC_being_altered = 64; // Procedure is getting altered
|
|
// This flag is used to make sure that MET_remove_procedure
|
|
// does not delete and remove procedure block from cache
|
|
// so dfw.epp:modify_procedure() can flip procedure body without
|
|
// invalidating procedure pointers from other parts of metadata cache
|
|
const USHORT PRC_check_existence = 128; // Existence lock released
|
|
|
|
const USHORT MAX_PROC_ALTER = 64; // No. of times an in-cache procedure can be altered
|
|
|
|
|
|
|
|
// Parameter block
|
|
|
|
class Parameter : public pool_alloc<type_prm>
|
|
{
|
|
public:
|
|
USHORT prm_number;
|
|
dsc prm_desc;
|
|
jrd_nod* prm_default_value;
|
|
Firebird::MetaName prm_name; // asciiz name
|
|
//public:
|
|
explicit Parameter(MemoryPool& p)
|
|
: prm_name(p)
|
|
{ }
|
|
};
|
|
|
|
// Index block to cache index information
|
|
|
|
class IndexBlock : public pool_alloc<type_idb>
|
|
{
|
|
public:
|
|
IndexBlock* idb_next;
|
|
jrd_nod* idb_expression; // node tree for index expression
|
|
jrd_req* idb_expression_request; // request in which index expression is evaluated
|
|
dsc idb_expression_desc; // descriptor for expression result
|
|
Lock* idb_lock; // lock to synchronize changes to index
|
|
USHORT idb_id;
|
|
};
|
|
|
|
|
|
|
|
// general purpose vector
|
|
template <class T, BlockType TYPE = type_vec>
|
|
class vec_base : protected pool_alloc<TYPE>
|
|
{
|
|
public:
|
|
typedef typename Firebird::Array<T>::iterator iterator;
|
|
typedef typename Firebird::Array<T>::const_iterator const_iterator;
|
|
/*
|
|
static vec_base* newVector(MemoryPool& p, int len)
|
|
{
|
|
return FB_NEW(p) vec_base<T, TYPE>(p, len);
|
|
}
|
|
static vec_base* newVector(MemoryPool& p, const vec_base& base)
|
|
{
|
|
return FB_NEW(p) vec_base<T, TYPE>(p, base);
|
|
}
|
|
*/
|
|
|
|
size_t count() const { return v.getCount(); }
|
|
T& operator[](size_t index) { return v[index]; }
|
|
const T& operator[](size_t index) const { return v[index]; }
|
|
|
|
iterator begin() { return v.begin(); }
|
|
iterator end() { return v.end(); }
|
|
|
|
const_iterator begin() const { return v.begin(); }
|
|
const_iterator end() const { return v.end(); }
|
|
|
|
void clear() { v.clear(); }
|
|
|
|
// T* memPtr() { return &*(v.begin()); }
|
|
T* memPtr() { return &v[0]; }
|
|
|
|
void resize(size_t n, T val = T()) { v.resize(n, val); }
|
|
|
|
void operator delete(void* mem) { MemoryPool::globalFree(mem); }
|
|
|
|
protected:
|
|
vec_base(MemoryPool& p, int len)
|
|
: v(p, len)
|
|
{
|
|
v.resize(len);
|
|
}
|
|
vec_base(MemoryPool& p, const vec_base& base)
|
|
: v(p)
|
|
{
|
|
v = base.v;
|
|
}
|
|
|
|
private:
|
|
Firebird::Array<T> v;
|
|
};
|
|
|
|
template <typename T>
|
|
class vec : public vec_base<T, type_vec>
|
|
{
|
|
public:
|
|
static vec* newVector(MemoryPool& p, int len)
|
|
{
|
|
return FB_NEW(p) vec<T>(p, len);
|
|
}
|
|
static vec* newVector(MemoryPool& p, const vec& base)
|
|
{
|
|
return FB_NEW(p) vec<T>(p, base);
|
|
}
|
|
static vec* newVector(MemoryPool& p, vec* base, int len)
|
|
{
|
|
if (!base)
|
|
base = FB_NEW(p) vec<T>(p, len);
|
|
else if (len > (int) base->count())
|
|
base->resize(len);
|
|
return base;
|
|
}
|
|
|
|
private:
|
|
vec(MemoryPool& p, int len) : vec_base<T, type_vec>(p, len) {}
|
|
vec(MemoryPool& p, const vec& base) : vec_base<T, type_vec>(p, base) {}
|
|
};
|
|
|
|
class vcl : public vec_base<SLONG, type_vcl>
|
|
{
|
|
public:
|
|
static vcl* newVector(MemoryPool& p, int len)
|
|
{
|
|
return FB_NEW(p) vcl(p, len);
|
|
}
|
|
static vcl* newVector(MemoryPool& p, const vcl& base)
|
|
{
|
|
return FB_NEW(p) vcl(p, base);
|
|
}
|
|
static vcl* newVector(MemoryPool& p, vcl* base, int len)
|
|
{
|
|
if (!base)
|
|
base = FB_NEW(p) vcl(p, len);
|
|
else if (len > (int) base->count())
|
|
base->resize(len);
|
|
return base;
|
|
}
|
|
|
|
private:
|
|
vcl(MemoryPool& p, int len) : vec_base<SLONG, type_vcl>(p, len) {}
|
|
vcl(MemoryPool& p, const vcl& base) : vec_base<SLONG, type_vcl>(p, base) {}
|
|
};
|
|
|
|
//#define TEST_VECTOR(vector, number) ((vector && number < vector->count()) ?
|
|
// (*vector)[number] : NULL)
|
|
|
|
|
|
//
|
|
// Transaction element block
|
|
//
|
|
struct teb
|
|
{
|
|
Attachment** teb_database;
|
|
int teb_tpb_length;
|
|
const UCHAR* teb_tpb;
|
|
};
|
|
|
|
typedef teb TEB;
|
|
|
|
// Window block for loading cached pages into
|
|
// CVC: Apparently, the only possible values are HEADER_PAGE==0 and LOG_PAGE==2
|
|
// and reside in ods.h, although I watched a place with 1 and others with members
|
|
// of a struct.
|
|
|
|
struct win
|
|
{
|
|
PageNumber win_page;
|
|
Ods::pag* win_buffer;
|
|
exp_index_buf* win_expanded_buffer;
|
|
class BufferDesc* win_bdb;
|
|
SSHORT win_scans;
|
|
USHORT win_flags;
|
|
// explicit win(SLONG wp) : win_page(wp), win_flags(0) {}
|
|
explicit win(const PageNumber& wp)
|
|
: win_page(wp), win_bdb(NULL), win_flags(0)
|
|
{}
|
|
win(const USHORT pageSpaceID, const SLONG pageNum)
|
|
: win_page(pageSpaceID, pageNum), win_bdb(NULL), win_flags(0)
|
|
{}
|
|
};
|
|
|
|
typedef win WIN;
|
|
|
|
// This is a compilation artifact: I wanted to be sure I would pick all old "win"
|
|
// declarations at the top, so "win" was built with a mandatory argument in
|
|
// the constructor. This struct satisfies a single place with an array. The
|
|
// alternative would be to initialize 16 elements of the array with 16 calls
|
|
// to the constructor: win my_array[n] = {win(-1), ... (win-1)};
|
|
// When all places are changed, this class can disappear and win's constructor
|
|
// may get the default value of -1 to "wp".
|
|
struct win_for_array: public win
|
|
{
|
|
win_for_array()
|
|
: win(DB_PAGE_SPACE, -1)
|
|
{}
|
|
};
|
|
|
|
// win_flags
|
|
|
|
const USHORT WIN_large_scan = 1; // large sequential scan
|
|
const USHORT WIN_secondary = 2; // secondary stream
|
|
const USHORT WIN_garbage_collector = 4; // garbage collector's window
|
|
const USHORT WIN_garbage_collect = 8; // scan left a page for garbage collector
|
|
|
|
|
|
// Thread specific database block
|
|
class thread_db : public ThreadData
|
|
{
|
|
private:
|
|
MemoryPool* tdbb_default;
|
|
void setDefaultPool(MemoryPool* p)
|
|
{
|
|
tdbb_default = p;
|
|
}
|
|
friend class Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool>;
|
|
Database* database;
|
|
Attachment* attachment;
|
|
jrd_tra* transaction;
|
|
jrd_req* request;
|
|
RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat;
|
|
|
|
public:
|
|
explicit thread_db(ISC_STATUS* status)
|
|
: ThreadData(ThreadData::tddDBB)
|
|
{
|
|
tdbb_default = NULL;
|
|
database = NULL;
|
|
attachment = NULL;
|
|
transaction = NULL;
|
|
request = NULL;
|
|
tdbb_quantum = QUANTUM;
|
|
tdbb_flags = 0;
|
|
tdbb_temp_traid = 0;
|
|
QUE_INIT(tdbb_latches);
|
|
reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy();
|
|
|
|
tdbb_status_vector = status;
|
|
fb_utils::init_status(tdbb_status_vector);
|
|
}
|
|
ISC_STATUS* tdbb_status_vector;
|
|
SSHORT tdbb_quantum; // Cycles remaining until voluntary schedule
|
|
USHORT tdbb_flags;
|
|
|
|
SLONG tdbb_temp_traid; // current temporary table scope
|
|
|
|
que tdbb_latches; // shared latches held by thread
|
|
|
|
MemoryPool* getDefaultPool()
|
|
{
|
|
return tdbb_default;
|
|
}
|
|
|
|
Database* getDatabase()
|
|
{
|
|
return database;
|
|
}
|
|
|
|
const Database* getDatabase() const
|
|
{
|
|
return database;
|
|
}
|
|
|
|
void setDatabase(Database* val)
|
|
{
|
|
database = val;
|
|
dbbStat = val ? &val->dbb_stats : RuntimeStatistics::getDummy();
|
|
}
|
|
|
|
Attachment* getAttachment()
|
|
{
|
|
return attachment;
|
|
}
|
|
|
|
const Attachment* getAttachment() const
|
|
{
|
|
return attachment;
|
|
}
|
|
|
|
void setAttachment(Attachment* val)
|
|
{
|
|
attachment = val;
|
|
attStat = val ? &val->att_stats : RuntimeStatistics::getDummy();
|
|
}
|
|
|
|
jrd_tra* getTransaction()
|
|
{
|
|
return transaction;
|
|
}
|
|
|
|
const jrd_tra* getTransaction() const
|
|
{
|
|
return transaction;
|
|
}
|
|
|
|
void setTransaction(jrd_tra* val);
|
|
|
|
jrd_req* getRequest()
|
|
{
|
|
return request;
|
|
}
|
|
|
|
const jrd_req* getRequest() const
|
|
{
|
|
return request;
|
|
}
|
|
|
|
void setRequest(jrd_req* val);
|
|
|
|
void bumpStats(const RuntimeStatistics::StatType index)
|
|
{
|
|
reqStat->bumpValue(index);
|
|
traStat->bumpValue(index);
|
|
attStat->bumpValue(index);
|
|
dbbStat->bumpValue(index);
|
|
}
|
|
|
|
void bumpStats(const RuntimeStatistics::StatType index, SLONG relation_id)
|
|
{
|
|
reqStat->bumpValue(index, relation_id);
|
|
//traStat->bumpValue(index, relation_id);
|
|
//attStat->bumpValue(index, relation_id);
|
|
//dbbStat->bumpValue(index, relation_id);
|
|
}
|
|
};
|
|
|
|
// tdbb_flags
|
|
|
|
const USHORT TDBB_sweeper = 1; // Thread sweeper or garbage collector
|
|
const USHORT TDBB_no_cache_unwind = 2; // Don't unwind page buffer cache
|
|
const USHORT TDBB_prc_being_dropped = 4; // Dropping a procedure
|
|
const USHORT TDBB_backup_write_locked = 8; // BackupManager has write lock on LCK_backup_database
|
|
const USHORT TDBB_stack_trace_done = 16; // PSQL stack trace is added into status-vector
|
|
const USHORT TDBB_shutdown_manager = 32; // Server shutdown thread
|
|
const USHORT TDBB_dont_post_dfw = 64; // dont post DFW tasks as deferred work is performed now
|
|
const USHORT TDBB_sys_error = 128; // error shouldn't be handled by the looper
|
|
const USHORT TDBB_verb_cleanup = 256; // verb cleanup is in progress
|
|
const USHORT TDBB_use_db_page_space = 512; // use database (not temporary) page space in GTT operations
|
|
|
|
|
|
class ThreadContextHolder
|
|
{
|
|
public:
|
|
explicit ThreadContextHolder(ISC_STATUS* status = NULL)
|
|
: context(status ? status : local_status)
|
|
{
|
|
context.putSpecific();
|
|
}
|
|
|
|
~ThreadContextHolder()
|
|
{
|
|
ThreadData::restoreSpecific();
|
|
}
|
|
|
|
thread_db* operator->()
|
|
{
|
|
return &context;
|
|
}
|
|
|
|
operator thread_db*()
|
|
{
|
|
return &context;
|
|
}
|
|
|
|
private:
|
|
// copying is prohibited
|
|
ThreadContextHolder(const ThreadContextHolder&);
|
|
ThreadContextHolder& operator= (const ThreadContextHolder&);
|
|
|
|
ISC_STATUS_ARRAY local_status;
|
|
thread_db context;
|
|
};
|
|
|
|
|
|
// CVC: This class was designed to restore the thread's default status vector automatically.
|
|
// In several places, tdbb_status_vector is replaced by a local temporary.
|
|
class ThreadStatusGuard
|
|
{
|
|
public:
|
|
explicit ThreadStatusGuard(thread_db* tdbb)
|
|
: m_tdbb(tdbb), m_old_status(tdbb->tdbb_status_vector)
|
|
{
|
|
fb_utils::init_status(m_local_status);
|
|
m_tdbb->tdbb_status_vector = m_local_status;
|
|
}
|
|
|
|
~ThreadStatusGuard()
|
|
{
|
|
m_tdbb->tdbb_status_vector = m_old_status;
|
|
}
|
|
|
|
//ISC_STATUS* restore()
|
|
//{
|
|
// return m_tdbb->tdbb_status_vector = m_old_status; // copy, not comparison
|
|
//}
|
|
|
|
operator ISC_STATUS*() { return m_local_status; }
|
|
|
|
void copyToOriginal()
|
|
{
|
|
memcpy(m_old_status, m_local_status, sizeof(ISC_STATUS_ARRAY));
|
|
}
|
|
|
|
private:
|
|
thread_db* const m_tdbb;
|
|
ISC_STATUS* const m_old_status;
|
|
ISC_STATUS_ARRAY m_local_status;
|
|
|
|
// copying is prohibited
|
|
ThreadStatusGuard(const ThreadStatusGuard&);
|
|
ThreadStatusGuard& operator=(const ThreadStatusGuard&);
|
|
};
|
|
|
|
|
|
// duplicate context of firebird string to store in jrd_nod::nod_arg
|
|
inline char* stringDup(MemoryPool& p, const Firebird::string& s)
|
|
{
|
|
char* rc = (char*) p.allocate(s.length() + 1
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
, __FILE__, __LINE__
|
|
#endif
|
|
);
|
|
strcpy(rc, s.c_str());
|
|
return rc;
|
|
}
|
|
|
|
inline char* stringDup(MemoryPool& p, const char* s, size_t l)
|
|
{
|
|
char* rc = (char*) p.allocate(l + 1
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
, __FILE__, __LINE__
|
|
#endif
|
|
);
|
|
memcpy(rc, s, l);
|
|
rc[l] = 0;
|
|
return rc;
|
|
}
|
|
|
|
inline char* stringDup(MemoryPool& p, const char* s)
|
|
{
|
|
if (! s)
|
|
{
|
|
return 0;
|
|
}
|
|
return stringDup(p, s, strlen(s));
|
|
}
|
|
|
|
// Used in string conversion calls
|
|
typedef Firebird::HalfStaticArray<UCHAR, 256> MoveBuffer;
|
|
|
|
} //namespace Jrd
|
|
|
|
// Lock levels
|
|
#include "../lock/lock.h"
|
|
|
|
// Random string block -- as long as impure areas don't have
|
|
// constructors and destructors, the need this varying string
|
|
|
|
class VaryingString : public pool_alloc_rpt<SCHAR, type_str>
|
|
{
|
|
public:
|
|
USHORT str_length;
|
|
UCHAR str_data[2]; // one byte for ALLOC and one for the NULL
|
|
};
|
|
|
|
// Threading macros
|
|
|
|
/* Define JRD_get_thread_data off the platform specific version.
|
|
* If we're in DEV mode, also do consistancy checks on the
|
|
* retrieved memory structure. This was originally done to
|
|
* track down cases of no "PUT_THREAD_DATA" on the NLM.
|
|
*
|
|
* This allows for NULL thread data (which might be an error by itself)
|
|
* If there is thread data,
|
|
* AND it is tagged as being a thread_db.
|
|
* AND it has a non-NULL database field,
|
|
* THEN we validate that the structure there is a database block.
|
|
* Otherwise, we return what we got.
|
|
* We can't always validate the database field, as during initialization
|
|
* there is no database set up.
|
|
*/
|
|
|
|
#if defined(DEV_BUILD)
|
|
#include "../jrd/err_proto.h"
|
|
|
|
inline Jrd::thread_db* JRD_get_thread_data()
|
|
{
|
|
ThreadData* p1 = ThreadData::getSpecific();
|
|
if (p1 && p1->getType() == ThreadData::tddDBB)
|
|
{
|
|
Jrd::thread_db* p2 = (Jrd::thread_db*) p1;
|
|
if (p2->getDatabase() && !p2->getDatabase()->checkHandle())
|
|
{
|
|
BUGCHECK(147);
|
|
}
|
|
}
|
|
return (Jrd::thread_db*) p1;
|
|
}
|
|
|
|
inline void CHECK_TDBB(const Jrd::thread_db* tdbb)
|
|
{
|
|
fb_assert(tdbb && (tdbb->getType() == ThreadData::tddDBB) &&
|
|
(!tdbb->getDatabase() || tdbb->getDatabase()->checkHandle()));
|
|
}
|
|
|
|
inline void CHECK_DBB(const Jrd::Database* dbb)
|
|
{
|
|
fb_assert(dbb->checkHandle());
|
|
}
|
|
|
|
#else // PROD_BUILD
|
|
|
|
inline Jrd::thread_db* JRD_get_thread_data()
|
|
{
|
|
return (Jrd::thread_db*) ThreadData::getSpecific();
|
|
}
|
|
|
|
inline void CHECK_DBB(const Jrd::Database* dbb)
|
|
{
|
|
}
|
|
|
|
inline void CHECK_TDBB(const Jrd::thread_db* tdbb)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
inline Jrd::Database* GET_DBB()
|
|
{
|
|
return JRD_get_thread_data()->getDatabase();
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*
|
|
* macros used to set thread_db and Database pointers when there are not set already *
|
|
*-------------------------------------------------------------------------*/
|
|
inline void SET_TDBB(Jrd::thread_db* &tdbb)
|
|
{
|
|
if (tdbb == NULL) {
|
|
tdbb = JRD_get_thread_data();
|
|
}
|
|
CHECK_TDBB(tdbb);
|
|
}
|
|
|
|
inline void SET_DBB(Jrd::Database* &dbb)
|
|
{
|
|
if (dbb == NULL) {
|
|
dbb = GET_DBB();
|
|
}
|
|
CHECK_DBB(dbb);
|
|
}
|
|
|
|
|
|
// global variables for engine
|
|
|
|
extern int debug;
|
|
|
|
namespace Jrd {
|
|
typedef Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool> ContextPoolHolder;
|
|
}
|
|
|
|
#endif // JRD_JRD_H
|