/* * 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* allocatedPages = newPages = FB_NEW(*dbb->dbb_permanent) RelationPages[BULK_ALLOC]; rel_pages_free = ++allocatedPages; for (size_t i = 1; i < BULK_ALLOC - 1; i++, allocatedPages++) allocatedPages->rel_next_free = allocatedPages + 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); 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; SelectivityList selectivity(*pool); 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; }