diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp new file mode 100644 index 0000000000..bf397caeb6 --- /dev/null +++ b/src/jrd/Relation.cpp @@ -0,0 +1,369 @@ +/* + * The contents of this file are subject to the Initial + * Developer's 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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * 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 Vlad Horsun + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2005 Vlad Horsun + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "../jrd/Relation.h" +#include "../jrd/tra.h" + +#include "../jrd/btr_proto.h" +#include "../jrd/dpm_proto.h" +#include "../jrd/idx_proto.h" +#include "../jrd/met_proto.h" +#include "../jrd/pag_proto.h" + +using namespace Jrd; + +#ifdef GARBAGE_THREAD + +void RelationGarbage::clear() +{ + TranGarbage *item = array.begin(), *const last = array.end(); + + for (; item < last; item++) + { + delete item->bm; + item->bm = NULL; + } + + array.clear(); +} + +void RelationGarbage::addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid) +{ + bool found = false; + TranGarbage const *item = array.begin(), *const last = array.end(); + + for (; item < last; item++) { + if (item->tran <= tranid) { + if (PageBitmap::test(item->bm, pageno)) { + found = true; + break; + } + } + else { + if (item->bm->clear(pageno)) + break; + } + } + + if (!found) { + PageBitmap *bm = NULL; + size_t pos = 0; + + if (array.find(tranid, pos) ) { + bm = array[pos].bm; + PBM_SET(pool, &bm, pageno); + } + else { + bm = NULL; + PBM_SET(pool, &bm, pageno); + array.add(TranGarbage(bm, tranid)); + } + } +} + +void RelationGarbage::getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm) +{ + while (array.getCount() > 0) + { + TranGarbage& garbage = array[0]; + + if (garbage.tran >= oldest_snapshot) + break; + + PageBitmap* bm_tran = garbage.bm; + PageBitmap** bm_or = PageBitmap::bit_or(sbm, &bm_tran); + if (*bm_or == garbage.bm) { + bm_tran = *sbm; + *sbm = garbage.bm; + garbage.bm = bm_tran; + } + delete garbage.bm; + + // Need to cast zero to exact type because literal zero means null pointer + array.remove(static_cast(0)); + } +} + +#endif //GARBAGE_THREAD + +RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, SLONG tran, bool allocPages) +{ + if (tdbb->tdbb_flags & TDBB_deferred) + return &rel_pages_base; + + Database* dbb = tdbb->tdbb_database; + SLONG inst_id; + if (rel_flags & REL_temp_tran) + { + if (tran > 0) + inst_id = tran; + else if (tdbb->tdbb_temp_traid) + inst_id = tdbb->tdbb_temp_traid; + else if (tdbb->tdbb_transaction) + inst_id = tdbb->tdbb_transaction->tra_number; + else // called without transaction, maybe from OPT or CMP ? + return &rel_pages_base; + } + else + { + if (tdbb->tdbb_temp_attid) + inst_id = tdbb->tdbb_temp_attid; + else + inst_id = PAG_attachment_id(tdbb); + } + + if (!rel_pages_inst) + { + JrdMemoryPool* pool = dbb->dbb_permanent; + rel_pages_inst = FB_NEW(*pool) RelationPagesInstances(*pool); + } + + size_t pos; + if (!rel_pages_inst->find(inst_id, pos)) + { + if (allocPages) + { + RelationPages* newPages = rel_pages_free; + if (!newPages) + { + const size_t BULK_ALLOC = 8; + + RelationPages* allocPages = newPages = + FB_NEW(*dbb->dbb_permanent) RelationPages[BULK_ALLOC]; + + rel_pages_free = ++allocPages; + for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocPages++) + allocPages->rel_next_free = allocPages + 1; + } + else + { + rel_pages_free = newPages->rel_next_free; + newPages->rel_next_free = 0; + } + + fb_assert(newPages->useCount == 0); + + newPages->addRef(); + newPages->rel_instance_id = inst_id; + newPages->rel_pg_space_id = dbb->dbb_page_manager.getTempPageSpaceID(tdbb); + PAG_attach_temp_pages(tdbb, newPages->rel_pg_space_id); + rel_pages_inst->add(newPages); + + // create primary pointer page and index root page + DPM_create_relation_pages(tdbb, this, newPages); + +#ifdef VIO_DEBUG + if (debug_flag > DEBUG_WRITES) + { + printf("jrd_rel::getPages inst %"SLONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n", + newPages->rel_instance_id, + newPages->rel_pages ? (*newPages->rel_pages)[0] : 0, + newPages->rel_index_root, + newPages); + } +#endif + + // create indexes + JrdMemoryPool *pool = tdbb->getDefaultPool(); + const bool poolCreated = !pool; + + if (poolCreated) + pool = JrdMemoryPool::createPool(); + Jrd::ContextPoolHolder context(tdbb, pool); + + SelectivityList selectivity(*pool); + + USHORT idx_id = 0; + while (true) + { + index_desc idx; + if (BTR_lookup(tdbb, this, idx_id, &idx, &rel_pages_base) != FB_SUCCESS) + break; + + Firebird::MetaName idx_name; + MET_lookup_index(tdbb, idx_name, this->rel_name, idx_id + 1); + + idx.idx_root = 0; + IDX_create_index(tdbb, this, &idx, idx_name.c_str(), NULL, + tdbb->tdbb_transaction, selectivity); + +#ifdef VIO_DEBUG + if (debug_flag > DEBUG_WRITES) + { + printf("jrd_rel::getPages inst %"SLONGFORMAT", irp %"SLONGFORMAT", idx %u, idx_root %"SLONGFORMAT", addr 0x%x\n", + newPages->rel_instance_id, + newPages->rel_index_root, + idx_id, + idx.idx_root, + newPages); + } +#endif + + idx_id++; + } + + if (poolCreated) + JrdMemoryPool::deletePool(pool); + + return newPages; + } // allocPages + else { + return 0; + } + } + else { + RelationPages* pages = (*rel_pages_inst)[pos]; + fb_assert(pages->rel_instance_id == inst_id); + return pages; + } +} + +bool jrd_rel::delPages(thread_db* tdbb, SLONG tran, RelationPages* aPages) +{ + RelationPages* pages = aPages ? aPages : getPages(tdbb, tran, false); + if (!pages || !pages->rel_instance_id) + return false; + + fb_assert((tran <= 0) || ((tran > 0) && (pages->rel_instance_id == tran))); + + fb_assert(pages->useCount > 0); + + if (--pages->useCount) + return false; + +#ifdef VIO_DEBUG + if (debug_flag > DEBUG_WRITES) + { + printf("jrd_rel::delPages inst %"SLONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n", + pages->rel_instance_id, + pages->rel_pages ? (*pages->rel_pages)[0] : 0, + pages->rel_index_root, + pages); + } +#endif + + size_t pos; + const bool found = rel_pages_inst->find(pages->rel_instance_id, pos); + fb_assert(found && ((*rel_pages_inst)[pos] == pages) ); + + rel_pages_inst->remove(pos); + + if (pages->rel_index_root) { + IDX_delete_indices(tdbb, this, pages); + } + + if (pages->rel_pages) { + DPM_delete_relation_pages(tdbb, this, pages); + } + + pages->free(rel_pages_free); + return true; +} + +void jrd_rel::getRelLockKey(thread_db* tdbb, UCHAR* key) +{ + *(USHORT*)key = rel_id; + key += sizeof(USHORT); + + const SLONG inst_id = getPages(tdbb)->rel_instance_id; + *(SLONG*)key = inst_id; +} + +SSHORT jrd_rel::getRelLockKeyLength() const +{ + return sizeof(USHORT) + sizeof(SLONG); +} + +void jrd_rel::cleanUp() +{ + if (rel_pages_inst) + delete rel_pages_inst; +} + + +void jrd_rel::fillPagesSnapshot(RelPagesSnapshot& snapshot, const bool attachmentOnly) +{ + if (rel_pages_inst) + { + for (size_t i = 0; i < rel_pages_inst->getCount(); i++) + { + RelationPages* relPages = (*rel_pages_inst)[i]; + + if (!attachmentOnly) + { + snapshot.add(relPages); + relPages->addRef(); + } + else if ((rel_flags & REL_temp_conn) && + (PAG_attachment_id(snapshot.spt_tdbb) == relPages->rel_instance_id)) + { + snapshot.add(relPages); + relPages->addRef(); + } + else if (rel_flags & REL_temp_tran) + { + const jrd_tra* tran = snapshot.spt_tdbb->tdbb_attachment->att_transactions; + for (; tran; tran = tran->tra_next) + { + if (tran->tra_number == relPages->rel_instance_id) + { + snapshot.add(relPages); + relPages->addRef(); + } + } + } + } + } + else + snapshot.add(&rel_pages_base); +} + +void jrd_rel::RelPagesSnapshot::clear() +{ +#ifdef DEV_BUILD + thread_db* tdbb = 0;; + SET_TDBB(tdbb); + fb_assert(tdbb == spt_tdbb); +#endif + + for (size_t i = 0; i < getCount(); i++) + { + RelationPages* relPages = (*this)[i]; + (*this)[i] = NULL; + + spt_relation->delPages(spt_tdbb, -1, relPages); + } + + inherited::clear(); +} + +void RelationPages::free(RelationPages*& nextFree) +{ + rel_next_free = nextFree; + nextFree = this; + + if (rel_pages) + rel_pages->clear(); + + rel_index_root = rel_data_pages = 0; + rel_slot_space = rel_data_space = rel_instance_id = 0; +} diff --git a/src/jrd/Relation.h b/src/jrd/Relation.h new file mode 100644 index 0000000000..bbd9c8bdfa --- /dev/null +++ b/src/jrd/Relation.h @@ -0,0 +1,302 @@ +/* + * 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 RELATION_H +#define RELATION_H + +#include "../jrd/jrd.h" +#include "../jrd/pag.h" +#include "../jrd/val.h" + +namespace Jrd +{ + +// view context block to cache view aliases + +class ViewContext +{ +public: + Firebird::MetaName vcx_context_name; + Firebird::MetaName vcx_relation_name; + USHORT vcx_context; + static const USHORT& generate(const void*, const ViewContext& vc) + { + return vc.vcx_context; + } +}; + +typedef Firebird::SortedArray, + USHORT, ViewContext> ViewContexts; + +#ifdef GARBAGE_THREAD + +class RelationGarbage +{ +private: + class TranGarbage { + public: + SLONG tran; + PageBitmap *bm; + + TranGarbage(PageBitmap *aBm, SLONG aTran) : tran(aTran), bm(aBm) {} + + static inline const SLONG generate(void const*, const TranGarbage& Item) + { return Item.tran; } + }; + + typedef Firebird::SortedArray< + TranGarbage, + Firebird::EmptyStorage, + SLONG, + TranGarbage> TranGarbageArray; + + TranGarbageArray array; + +public: + explicit RelationGarbage(MemoryPool& p) : array(p) {} + ~RelationGarbage() { clear(); } + + void addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid); + void clear(); + + void getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm); + + SLONG minTranID() const + { return (array.getCount() > 0) ? array[0].tran : MAX_SLONG; } +}; + +#endif //GARBAGE_THREAD + +class RelationPages +{ +public: + vcl* rel_pages; // vector of pointer page numbers + SLONG rel_instance_id; // 0 or att_attachment_id or tra_number + SLONG rel_index_root; // index root page number + SLONG rel_data_pages; // count of relation data pages + USHORT rel_slot_space; // lowest pointer page with slot space + USHORT rel_data_space; // lowest pointer page with data page space + USHORT rel_pg_space_id; + + RelationPages() + { + rel_pages = 0; + rel_index_root = rel_data_pages = rel_instance_id = 0; + rel_slot_space = rel_data_space = 0; + rel_pg_space_id = DB_PAGE_SPACE; + rel_next_free = 0; + useCount = 0; + } + + inline SLONG addRef() + { + return useCount++; + } + + void free(RelationPages*& nextFree); + + static inline SLONG generate(const void*, const RelationPages* item) + { + return item->rel_instance_id; + } + +private: + RelationPages* rel_next_free; + SLONG useCount; + +friend class jrd_rel; +}; + + +// Primary dependencies from all foreign references to relation's +// primary/unique keys + +struct prim { + vec* prim_reference_ids; + vec* prim_relations; + vec* prim_indexes; +}; + + +// Foreign references to other relations' primary/unique keys + +struct frgn { + vec* frgn_reference_ids; + vec* frgn_relations; + vec* frgn_indexes; +}; + +// Relation block; one is created for each relation referenced +// in the database, though it is not really filled out until +// the relation is scanned + +class jrd_rel : public pool_alloc +{ +public: + USHORT rel_id; + USHORT rel_flags; + USHORT rel_current_fmt; // Current format number + Format* rel_current_format; // Current record format + Firebird::MetaName rel_name; // ascii relation name + vec* rel_formats; // Known record formats + Firebird::MetaName rel_owner_name; // ascii owner + vec* rel_fields; // vector of field blocks + + RecordSelExpr* rel_view_rse; // view record select expression + ViewContexts rel_view_contexts; // sorted array of view contexts + + Firebird::MetaName rel_security_name; // security class name for relation + ExternalFile* rel_file; // external file name + + vec* rel_gc_rec; // vector of records for garbage collection +#ifdef GARBAGE_THREAD + PageBitmap* rel_gc_bitmap; // garbage collect bitmap of data page sequences + RelationGarbage* rel_garbage; // deferred gc bitmap's by tran numbers +#endif + + USHORT rel_use_count; // requests compiled with relation + USHORT rel_sweep_count; // sweep and/or garbage collector threads active + SSHORT rel_scan_count; // concurrent sequential scan count + + Lock* rel_existence_lock; // existence lock, if any + Lock* rel_partners_lock; // partners lock + IndexLock* rel_index_locks; // index existence locks + IndexBlock* rel_index_blocks; // index blocks for caching index info + trig_vec* rel_pre_erase; // Pre-operation erase trigger + trig_vec* rel_post_erase; // Post-operation erase trigger + trig_vec* rel_pre_modify; // Pre-operation modify trigger + trig_vec* rel_post_modify; // Post-operation modify trigger + trig_vec* rel_pre_store; // Pre-operation store trigger + trig_vec* rel_post_store; // Post-operation store trigger + prim rel_primary_dpnds; // foreign dependencies on this relation's primary key + frgn rel_foreign_refs; // foreign references to other relations' primary keys + + // global temporary relations attributes + inline RelationPages* getPages(thread_db* tdbb, SLONG tran = -1, bool allocPages = true); + + inline RelationPages* getBasePages() + { + return &rel_pages_base; + } + + bool delPages(thread_db* tdbb, SLONG tran = -1, RelationPages* aPages = 0); + + void getRelLockKey(thread_db* tdbb, UCHAR* key); + SSHORT getRelLockKeyLength() const; + + void cleanUp(); + + class RelPagesSnapshot : public Firebird::Array + { + public: + typedef Firebird::Array inherited; + + RelPagesSnapshot(thread_db* tdbb, jrd_rel* relation) { + spt_tdbb = tdbb; + spt_relation = relation; + } + + ~RelPagesSnapshot() { + clear(); + } + + void clear(); + private: + thread_db* spt_tdbb; + jrd_rel* spt_relation; + + friend class jrd_rel; + }; + + void fillPagesSnapshot(RelPagesSnapshot&, const bool AttachmentOnly = false); + +private: + typedef Firebird::SortedArray< + RelationPages*, + Firebird::EmptyStorage, + SLONG, + RelationPages> + RelationPagesInstances; + + RelationPagesInstances* rel_pages_inst; + RelationPages rel_pages_base; + RelationPages* rel_pages_free; + + RelationPages* getPagesInternal(thread_db* tdbb, SLONG tran, bool allocPages); + +public: + explicit jrd_rel(MemoryPool& p) + : rel_name(p), rel_owner_name(p), rel_view_contexts(p), rel_security_name(p) { } +}; + +// rel_flags + +const USHORT REL_scanned = 0x0001; // Field expressions scanned (or being scanned) +const USHORT REL_system = 0x0002; +const USHORT REL_deleted = 0x0004; // Relation known gonzo +const USHORT REL_get_dependencies = 0x0008; // New relation needs dependencies during scan +const USHORT REL_force_scan = 0x0010; // system relation has been updated since ODS change, force a scan +const USHORT REL_check_existence = 0x0020; // Existence lock released pending drop of relation +const USHORT REL_blocking = 0x0040; // Blocking someone from dropping relation +const USHORT REL_sys_triggers = 0x0080; // The relation has system triggers to compile +const USHORT REL_sql_relation = 0x0100; // Relation defined as sql table +const USHORT REL_check_partners = 0x0200; // Rescan primary dependencies and foreign references +const USHORT REL_being_scanned = 0x0400; // relation scan in progress +const USHORT REL_sys_trigs_being_loaded = 0x0800; // System triggers being loaded +const USHORT REL_deleting = 0x1000; // relation delete in progress +const USHORT REL_temp_tran = 0x2000; // relation is a GTT delete rows +const USHORT REL_temp_conn = 0x4000; // relation is a GTT preserve rows + +const USHORT REL_IS_TEMP = REL_temp_tran | REL_temp_conn; + + +inline RelationPages* jrd_rel::getPages(thread_db* tdbb, SLONG tran, bool allocPages) +{ + if (!(rel_flags & REL_IS_TEMP)) + return &rel_pages_base; + else + return getPagesInternal(tdbb, tran, allocPages); +} + + +// Field block, one for each field in a scanned relation + +class jrd_fld : public pool_alloc +{ +public: + jrd_nod* fld_validation; // validation clause, if any + jrd_nod* fld_not_null; // if field cannot be NULL + jrd_nod* fld_missing_value; // missing value, if any + jrd_nod* fld_computation; // computation for virtual field + jrd_nod* fld_source; // source for view fields + jrd_nod* fld_default_value; // default value, if any + ArrayField* fld_array; // array description, if array + Firebird::MetaName fld_name; // Field name + Firebird::MetaName fld_security_name; // security class name for field + +public: + explicit jrd_fld(MemoryPool& p) + : fld_name(p), fld_security_name(p) { } +}; + +} + +#endif \ No newline at end of file diff --git a/src/jrd/exe.h b/src/jrd/exe.h index 0ea7b7877e..4b5d05c39b 100644 --- a/src/jrd/exe.h +++ b/src/jrd/exe.h @@ -33,6 +33,7 @@ #include "../jrd/jrd_blks.h" #include "../jrd/blb.h" +#include "../jrd/Relation.h" #include "../common/classes/array.h" #include "../common/classes/MetaName.h" diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index 7bfd8dbbd1..e29c095a38 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -612,26 +612,6 @@ public: explicit Parameter(MemoryPool& p) : prm_name(p) { } }; - -/* Primary dependencies from all foreign references to relation's - primary/unique keys */ - -struct prim { - vec* prim_reference_ids; - vec* prim_relations; - vec* prim_indexes; -}; - - -/* Foreign references to other relations' primary/unique keys */ - -struct frgn { - vec* frgn_reference_ids; - vec* frgn_relations; - vec* frgn_indexes; -}; - - // Relation trigger definition class Trigger { @@ -652,260 +632,6 @@ public: typedef Firebird::ObjectsArray trig_vec; -#ifdef GARBAGE_THREAD - -class RelationGarbage -{ -private: - class TranGarbage { - public: - SLONG tran; - PageBitmap *bm; - - TranGarbage(PageBitmap *aBm, SLONG aTran) : tran(aTran), bm(aBm) {} - - static inline const SLONG generate(void const*, const TranGarbage& Item) - { return Item.tran; } - }; - - typedef Firebird::SortedArray< - TranGarbage, - Firebird::EmptyStorage, - SLONG, - TranGarbage> TranGarbageArray; - - TranGarbageArray array; - -public: - explicit RelationGarbage(MemoryPool& p) : array(p) {} - ~RelationGarbage() { clear(); } - - void addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid); - void clear(); - - void getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm); - - SLONG minTranID() const - { return (array.getCount() > 0) ? array[0].tran : MAX_SLONG; } -}; - -#endif //GARBAGE_THREAD - - -/* view context block to cache view aliases */ - -class ViewContext -{ -public: - Firebird::MetaName vcx_context_name; - Firebird::MetaName vcx_relation_name; - USHORT vcx_context; - static const USHORT& generate(const void*, const ViewContext& vc) - { - return vc.vcx_context; - } -}; - -typedef Firebird::SortedArray, - USHORT, ViewContext> ViewContexts; - -class RelationPages -{ -public: - vcl* rel_pages; // vector of pointer page numbers - SLONG rel_index_root; // index root page number - SLONG rel_data_pages; // count of relation data pages - USHORT rel_slot_space; // lowest pointer page with slot space - USHORT rel_data_space; // lowest pointer page with data page space - - SLONG rel_instance_id; // 0 or att_attachment_id or tra_number - USHORT rel_pg_space_id; - - RelationPages() - { - rel_pages = 0; - rel_index_root = rel_data_pages = rel_instance_id = 0; - rel_slot_space = rel_data_space = 0; - rel_pg_space_id = DB_PAGE_SPACE; - rel_next_free = 0; - useCount = 0; - } - - inline SLONG addRef() - { - return useCount++; - } - - void free(RelationPages*& nextFree); - - static inline SLONG generate(const void*, const RelationPages* item) - { - return item->rel_instance_id; - } - -private: - RelationPages* rel_next_free; - SLONG useCount; - -friend class jrd_rel; -}; - - -/* Relation block; one is created for each relation referenced - in the database, though it is not really filled out until - the relation is scanned */ - -class jrd_rel : public pool_alloc -{ -public: - USHORT rel_id; - USHORT rel_flags; - USHORT rel_current_fmt; /* Current format number */ - Format* rel_current_format; /* Current record format */ - Firebird::MetaName rel_name; /* ascii relation name */ - vec* rel_formats; /* Known record formats */ - Firebird::MetaName rel_owner_name; /* ascii owner */ - vec* rel_fields; /* vector of field blocks */ - - RecordSelExpr* rel_view_rse; /* view record select expression */ - ViewContexts rel_view_contexts; /* sorted array of view contexts */ - - Firebird::MetaName rel_security_name; /* security class name for relation */ - ExternalFile* rel_file; /* external file name */ - - vec* rel_gc_rec; /* vector of records for garbage collection */ -#ifdef GARBAGE_THREAD - PageBitmap* rel_gc_bitmap; /* garbage collect bitmap of data page sequences */ - RelationGarbage* rel_garbage; /* deferred gc bitmap's by tran numbers */ -#endif - - USHORT rel_use_count; /* requests compiled with relation */ - USHORT rel_sweep_count; /* sweep and/or garbage collector threads active */ - SSHORT rel_scan_count; /* concurrent sequential scan count */ - - Lock* rel_existence_lock; /* existence lock, if any */ - Lock* rel_partners_lock; /* partners lock */ - IndexLock* rel_index_locks; /* index existence locks */ - IndexBlock* rel_index_blocks; /* index blocks for caching index info */ - trig_vec* rel_pre_erase; /* Pre-operation erase trigger */ - trig_vec* rel_post_erase; /* Post-operation erase trigger */ - trig_vec* rel_pre_modify; /* Pre-operation modify trigger */ - trig_vec* rel_post_modify; /* Post-operation modify trigger */ - trig_vec* rel_pre_store; /* Pre-operation store trigger */ - trig_vec* rel_post_store; /* Post-operation store trigger */ - prim rel_primary_dpnds; /* foreign dependencies on this relation's primary key */ - frgn rel_foreign_refs; /* foreign references to other relations' primary keys */ - - // global temporary relations attributes - inline RelationPages* getPages(thread_db* tdbb, SLONG tran = -1, bool allocPages = true); - - inline RelationPages* getBasePages() - { - return &rel_pages_base; - } - - bool delPages(thread_db* tdbb, SLONG tran = -1, RelationPages* aPages = 0); - - void getRelLockKey(thread_db* tdbb, UCHAR* key); - SSHORT getRelLockKeyLength() const; - - void cleanUp(); - - class RelPagesSnapshot : public Firebird::Array - { - public: - typedef Firebird::Array inherited; - - RelPagesSnapshot(thread_db* tdbb, jrd_rel* relation) { - spt_tdbb = tdbb; - spt_relation = relation; - } - - ~RelPagesSnapshot() { - clear(); - } - - void clear(); - private: - thread_db* spt_tdbb; - jrd_rel* spt_relation; - - friend class jrd_rel; - }; - - void fillPagesSnapshot(RelPagesSnapshot&, const bool AttachmentOnly = false); - -private: - typedef Firebird::SortedArray< - RelationPages*, - Firebird::EmptyStorage, - SLONG, - RelationPages> - RelationPagesInstances; - - RelationPagesInstances* rel_pages_inst; - RelationPages rel_pages_base; - RelationPages* rel_pages_free; - - RelationPages* getPagesInternal(thread_db* tdbb, SLONG tran, bool allocPages); - -public: - explicit jrd_rel(MemoryPool& p) - : rel_name(p), rel_owner_name(p), rel_view_contexts(p), rel_security_name(p) { } -}; - -// rel_flags - -const USHORT REL_scanned = 0x0001; /* Field expressions scanned (or being scanned) */ -const USHORT REL_system = 0x0002; -const USHORT REL_deleted = 0x0004; /* Relation known gonzo */ -const USHORT REL_get_dependencies = 0x0008; /* New relation needs dependencies during scan */ -const USHORT REL_force_scan = 0x0010; /* system relation has been updated since ODS change, force a scan */ -const USHORT REL_check_existence = 0x0020; /* Existence lock released pending drop of relation */ -const USHORT REL_blocking = 0x0040; /* Blocking someone from dropping relation */ -const USHORT REL_sys_triggers = 0x0080; /* The relation has system triggers to compile */ -const USHORT REL_sql_relation = 0x0100; /* Relation defined as sql table */ -const USHORT REL_check_partners = 0x0200; /* Rescan primary dependencies and foreign references */ -const USHORT REL_being_scanned = 0x0400; /* relation scan in progress */ -const USHORT REL_sys_trigs_being_loaded = 0x0800; /* System triggers being loaded */ -const USHORT REL_deleting = 0x1000; /* relation delete in progress */ -const USHORT REL_temp_tran = 0x2000; /* relation is a GTT delete rows */ -const USHORT REL_temp_conn = 0x4000; /* relation is a GTT preserve rows */ - -const USHORT REL_IS_TEMP = REL_temp_tran | REL_temp_conn; - - -inline RelationPages* jrd_rel::getPages(thread_db* tdbb, SLONG tran, bool allocPages) -{ - if (!(rel_flags & REL_IS_TEMP)) - return &rel_pages_base; - else - return getPagesInternal(tdbb, tran, allocPages); -} - - -/* Field block, one for each field in a scanned relation */ - -class jrd_fld : public pool_alloc -{ -public: - jrd_nod* fld_validation; /* validation clause, if any */ - jrd_nod* fld_not_null; /* if field cannot be NULL */ - jrd_nod* fld_missing_value; /* missing value, if any */ - jrd_nod* fld_computation; /* computation for virtual field */ - jrd_nod* fld_source; /* source for view fields */ - jrd_nod* fld_default_value; /* default value, if any */ - ArrayField* fld_array; /* array description, if array */ - Firebird::MetaName fld_name; /* Field name */ - Firebird::MetaName fld_security_name; /* security class name for field */ - -public: - explicit jrd_fld(MemoryPool& p) - : fld_name(p), fld_security_name(p) { } -}; - - - /* Index block to cache index information */ class IndexBlock : public pool_alloc diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index db0176823c..4db229134b 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -5004,340 +5004,3 @@ static void verb_post( garbage_collect_idx(tdbb, rpb, new_rpb, old_data); } } - -#ifdef GARBAGE_THREAD - -void RelationGarbage::clear() -{ - TranGarbage *item = array.begin(), *const last = array.end(); - - for (; item < last; item++) - { - delete item->bm; - item->bm = NULL; - } - - array.clear(); -} - -void RelationGarbage::addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid) -{ - bool found = false; - TranGarbage const *item = array.begin(), *const last = array.end(); - - for (; item < last; item++) { - if (item->tran <= tranid) { - if (PageBitmap::test(item->bm, pageno)) { - found = true; - break; - } - } - else { - if (item->bm->clear(pageno)) - break; - } - } - - if (!found) { - PageBitmap *bm = NULL; - size_t pos = 0; - - if (array.find(tranid, pos) ) { - bm = array[pos].bm; - PBM_SET(pool, &bm, pageno); - } - else { - bm = NULL; - PBM_SET(pool, &bm, pageno); - array.add(TranGarbage(bm, tranid)); - } - } -} - -void RelationGarbage::getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm) -{ - while (array.getCount() > 0) - { - TranGarbage& garbage = array[0]; - - if (garbage.tran >= oldest_snapshot) - break; - - PageBitmap* bm_tran = garbage.bm; - PageBitmap** bm_or = PageBitmap::bit_or(sbm, &bm_tran); - if (*bm_or == garbage.bm) { - bm_tran = *sbm; - *sbm = garbage.bm; - garbage.bm = bm_tran; - } - delete garbage.bm; - - // Need to cast zero to exact type because literal zero means null pointer - array.remove(static_cast(0)); - } -} - -#endif //GARBAGE_THREAD - -RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, SLONG tran, bool allocPages) -{ - if (tdbb->tdbb_flags & TDBB_deferred) - return &rel_pages_base; - - Database* dbb = tdbb->tdbb_database; - SLONG inst_id; - if (rel_flags & REL_temp_tran) - { - if (tran > 0) - inst_id = tran; - else if (tdbb->tdbb_temp_traid) - inst_id = tdbb->tdbb_temp_traid; - else if (tdbb->tdbb_transaction) - inst_id = tdbb->tdbb_transaction->tra_number; - else // called without transaction, maybe from OPT or CMP ? - return &rel_pages_base; - } - else - { - if (tdbb->tdbb_temp_attid) - inst_id = tdbb->tdbb_temp_attid; - else - inst_id = PAG_attachment_id(tdbb); - } - - if (!rel_pages_inst) - { - JrdMemoryPool* pool = dbb->dbb_permanent; - rel_pages_inst = FB_NEW(*pool) RelationPagesInstances(*pool); - } - - size_t pos; - if (!rel_pages_inst->find(inst_id, pos)) - { - if (allocPages) - { - RelationPages* newPages = rel_pages_free; - if (!newPages) - { - const size_t BULK_ALLOC = 8; - - RelationPages* allocPages = newPages = - FB_NEW(*dbb->dbb_permanent) RelationPages[BULK_ALLOC]; - - rel_pages_free = ++allocPages; - for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocPages++) - allocPages->rel_next_free = allocPages + 1; - } - else - { - rel_pages_free = newPages->rel_next_free; - newPages->rel_next_free = 0; - } - - fb_assert(newPages->useCount == 0); - - newPages->addRef(); - newPages->rel_instance_id = inst_id; - newPages->rel_pg_space_id = dbb->dbb_page_manager.getTempPageSpaceID(tdbb); - PAG_attach_temp_pages(tdbb, newPages->rel_pg_space_id); - rel_pages_inst->add(newPages); - - // create primary pointer page and index root page - DPM_create_relation_pages(tdbb, this, newPages); - -#ifdef VIO_DEBUG - if (debug_flag > DEBUG_WRITES) - { - printf("jrd_rel::getPages inst %"SLONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n", - newPages->rel_instance_id, - newPages->rel_pages ? (*newPages->rel_pages)[0] : 0, - newPages->rel_index_root, - newPages); - } -#endif - - // create indexes - JrdMemoryPool *pool = tdbb->getDefaultPool(); - const bool poolCreated = !pool; - - if (poolCreated) - pool = JrdMemoryPool::createPool(); - Jrd::ContextPoolHolder context(tdbb, pool); - - SelectivityList selectivity(*pool); - - USHORT idx_id = 0; - while (true) - { - index_desc idx; - if (BTR_lookup(tdbb, this, idx_id, &idx, &rel_pages_base) != FB_SUCCESS) - break; - - Firebird::MetaName idx_name; - MET_lookup_index(tdbb, idx_name, this->rel_name, idx_id + 1); - - idx.idx_root = 0; - IDX_create_index(tdbb, this, &idx, idx_name.c_str(), NULL, - tdbb->tdbb_transaction, selectivity); - -#ifdef VIO_DEBUG - if (debug_flag > DEBUG_WRITES) - { - printf("jrd_rel::getPages inst %"SLONGFORMAT", irp %"SLONGFORMAT", idx %u, idx_root %"SLONGFORMAT", addr 0x%x\n", - newPages->rel_instance_id, - newPages->rel_index_root, - idx_id, - idx.idx_root, - newPages); - } -#endif - - idx_id++; - } - - if (poolCreated) - JrdMemoryPool::deletePool(pool); - - return newPages; - } // allocPages - else { - return 0; - } - } - else { - RelationPages* pages = (*rel_pages_inst)[pos]; - fb_assert(pages->rel_instance_id == inst_id); - return pages; - } -} - -bool jrd_rel::delPages(thread_db* tdbb, SLONG tran, RelationPages* aPages) -{ - RelationPages* pages = aPages ? aPages : getPages(tdbb, tran, false); - if (!pages || !pages->rel_instance_id) - return false; - - fb_assert((tran <= 0) || ((tran > 0) && (pages->rel_instance_id == tran))); - - fb_assert(pages->useCount > 0); - - if (--pages->useCount) - return false; - -#ifdef VIO_DEBUG - if (debug_flag > DEBUG_WRITES) - { - printf("jrd_rel::delPages inst %"SLONGFORMAT", ppp %"SLONGFORMAT", irp %"SLONGFORMAT", addr 0x%x\n", - pages->rel_instance_id, - pages->rel_pages ? (*pages->rel_pages)[0] : 0, - pages->rel_index_root, - pages); - } -#endif - - size_t pos; - const bool found = rel_pages_inst->find(pages->rel_instance_id, pos); - fb_assert(found && ((*rel_pages_inst)[pos] == pages) ); - - rel_pages_inst->remove(pos); - - if (pages->rel_index_root) { - IDX_delete_indices(tdbb, this, pages); - } - - if (pages->rel_pages) { - DPM_delete_relation_pages(tdbb, this, pages); - } - - pages->free(rel_pages_free); - return true; -} - -void jrd_rel::getRelLockKey(thread_db* tdbb, UCHAR* key) -{ - *(USHORT*)key = rel_id; - key += sizeof(USHORT); - - const SLONG inst_id = getPages(tdbb)->rel_instance_id; - *(SLONG*)key = inst_id; -} - -SSHORT jrd_rel::getRelLockKeyLength() const -{ - return sizeof(USHORT) + sizeof(SLONG); -} - -void jrd_rel::cleanUp() -{ - if (rel_pages_inst) - delete rel_pages_inst; -} - - -void jrd_rel::fillPagesSnapshot(RelPagesSnapshot& snapshot, const bool attachmentOnly) -{ - if (rel_pages_inst) - { - for (size_t i = 0; i < rel_pages_inst->getCount(); i++) - { - RelationPages* relPages = (*rel_pages_inst)[i]; - - if (!attachmentOnly) - { - snapshot.add(relPages); - relPages->addRef(); - } - else if ((rel_flags & REL_temp_conn) && - (PAG_attachment_id(snapshot.spt_tdbb) == relPages->rel_instance_id)) - { - snapshot.add(relPages); - relPages->addRef(); - } - else if (rel_flags & REL_temp_tran) - { - const jrd_tra* tran = snapshot.spt_tdbb->tdbb_attachment->att_transactions; - for (; tran; tran = tran->tra_next) - { - if (tran->tra_number == relPages->rel_instance_id) - { - snapshot.add(relPages); - relPages->addRef(); - } - } - } - } - } - else - snapshot.add(&rel_pages_base); -} - -void jrd_rel::RelPagesSnapshot::clear() -{ -#ifdef DEV_BUILD - thread_db* tdbb = 0;; - SET_TDBB(tdbb); - fb_assert(tdbb == spt_tdbb); -#endif - - for (size_t i = 0; i < getCount(); i++) - { - RelationPages* relPages = (*this)[i]; - (*this)[i] = NULL; - - spt_relation->delPages(spt_tdbb, -1, relPages); - } - - inherited::clear(); -} - -void RelationPages::free(RelationPages*& nextFree) -{ - rel_next_free = nextFree; - nextFree = this; - - if (rel_pages) - rel_pages->clear(); - - rel_index_root = rel_data_pages = 0; - rel_slot_space = rel_data_space = rel_instance_id = 0; -}