mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 20:43:03 +01:00
Move relation stuff from jrd.h\vio.cpp into new Relation.h\Relation.cpp
by request of Claudio and Dmitry
This commit is contained in:
parent
4ac686a861
commit
8e14bc4f1e
369
src/jrd/Relation.cpp
Normal file
369
src/jrd/Relation.cpp
Normal file
@ -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 <hvlad@users.sourceforge.net>
|
||||||
|
* 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<size_t>(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;
|
||||||
|
}
|
302
src/jrd/Relation.h
Normal file
302
src/jrd/Relation.h
Normal file
@ -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<ViewContext, Firebird::EmptyStorage<ViewContext>,
|
||||||
|
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<TranGarbage>,
|
||||||
|
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<int>* prim_reference_ids;
|
||||||
|
vec<int>* prim_relations;
|
||||||
|
vec<int>* prim_indexes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Foreign references to other relations' primary/unique keys
|
||||||
|
|
||||||
|
struct frgn {
|
||||||
|
vec<int>* frgn_reference_ids;
|
||||||
|
vec<int>* frgn_relations;
|
||||||
|
vec<int>* 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<type_rel>
|
||||||
|
{
|
||||||
|
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<Format*>* rel_formats; // Known record formats
|
||||||
|
Firebird::MetaName rel_owner_name; // ascii owner
|
||||||
|
vec<jrd_fld*>* 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<Record*>* 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<RelationPages*>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Firebird::Array<RelationPages*> 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<RelationPages*>,
|
||||||
|
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<type_fld>
|
||||||
|
{
|
||||||
|
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
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "../jrd/jrd_blks.h"
|
#include "../jrd/jrd_blks.h"
|
||||||
#include "../jrd/blb.h"
|
#include "../jrd/blb.h"
|
||||||
|
#include "../jrd/Relation.h"
|
||||||
#include "../common/classes/array.h"
|
#include "../common/classes/array.h"
|
||||||
#include "../common/classes/MetaName.h"
|
#include "../common/classes/MetaName.h"
|
||||||
|
|
||||||
|
274
src/jrd/jrd.h
274
src/jrd/jrd.h
@ -612,26 +612,6 @@ public:
|
|||||||
explicit Parameter(MemoryPool& p) : prm_name(p) { }
|
explicit Parameter(MemoryPool& p) : prm_name(p) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Primary dependencies from all foreign references to relation's
|
|
||||||
primary/unique keys */
|
|
||||||
|
|
||||||
struct prim {
|
|
||||||
vec<int>* prim_reference_ids;
|
|
||||||
vec<int>* prim_relations;
|
|
||||||
vec<int>* prim_indexes;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Foreign references to other relations' primary/unique keys */
|
|
||||||
|
|
||||||
struct frgn {
|
|
||||||
vec<int>* frgn_reference_ids;
|
|
||||||
vec<int>* frgn_relations;
|
|
||||||
vec<int>* frgn_indexes;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Relation trigger definition
|
// Relation trigger definition
|
||||||
|
|
||||||
class Trigger {
|
class Trigger {
|
||||||
@ -652,260 +632,6 @@ public:
|
|||||||
|
|
||||||
typedef Firebird::ObjectsArray<Trigger> trig_vec;
|
typedef Firebird::ObjectsArray<Trigger> 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<TranGarbage>,
|
|
||||||
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<ViewContext, Firebird::EmptyStorage<ViewContext>,
|
|
||||||
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<type_rel>
|
|
||||||
{
|
|
||||||
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<Format*>* rel_formats; /* Known record formats */
|
|
||||||
Firebird::MetaName rel_owner_name; /* ascii owner */
|
|
||||||
vec<jrd_fld*>* 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<Record*>* 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<RelationPages*>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Firebird::Array<RelationPages*> 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<RelationPages*>,
|
|
||||||
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<type_fld>
|
|
||||||
{
|
|
||||||
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 */
|
/* Index block to cache index information */
|
||||||
|
|
||||||
class IndexBlock : public pool_alloc<type_idb>
|
class IndexBlock : public pool_alloc<type_idb>
|
||||||
|
337
src/jrd/vio.cpp
337
src/jrd/vio.cpp
@ -5004,340 +5004,3 @@ static void verb_post(
|
|||||||
garbage_collect_idx(tdbb, rpb, new_rpb, old_data);
|
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<size_t>(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;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user