8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

WIP - take into an account states of an object (needs load / normal / erased)

This commit is contained in:
AlexPeshkoff 2023-12-15 20:18:28 +03:00
parent 4215b9d220
commit 7736734e91
87 changed files with 3755 additions and 10995 deletions

View File

@ -72,7 +72,7 @@ protected:
template <typename T, typename Storage = EmptyStorage<T> >
class Array : protected Storage
{
static_assert(std::is_trivially_copyable<T>(), "Only simple (trivially copyable) types supported in array");
// !!!!! temp commemnted out - FastLoadLevel failure static_assert(std::is_trivially_copyable<T>(), "Only simple (trivially copyable) types supported in array");
public:
typedef FB_SIZE_T size_type;
@ -421,7 +421,7 @@ public:
data = this->getStorage();
}
// This method only assigns "pos" if the element is found.
// This methods only assigns "pos" if the element is found.
// Maybe we should modify it to iterate directy with "pos".
bool find(const T& item, size_type& pos) const
{
@ -436,6 +436,19 @@ public:
return false;
}
bool find(std::function<int(const T& item)> compare, size_type& pos) const
{
for (size_type i = 0; i < count; i++)
{
if (compare(data[i]) == 0)
{
pos = i;
return true;
}
}
return false;
}
bool findAndRemove(const T& item)
{
size_type pos;

View File

@ -30,13 +30,11 @@
namespace Jrd {
class Resources;
class NodePrinter
{
public:
NodePrinter(const Resources* aResources, unsigned aIndent = 0)
: indent(aIndent), resources(aResources)
NodePrinter(unsigned aIndent = 0)
: indent(aIndent)
{
}
@ -339,9 +337,6 @@ private:
private:
unsigned indent;
public:
const Resources* resources;
private:
Firebird::ObjectsArray<Firebird::string> stack;
Firebird::string text;

View File

@ -2696,7 +2696,7 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, Request* request, WhichTrigger
preModifyEraseTriggers(tdbb, &relation->rel_pre_erase, whichTrig, rpb, NULL, TRIGGER_DELETE);
if (relation->rel_file)
EXT_erase(rpb, transaction);
rel_file->erase(rpb, transaction);
else if (relation->isVirtual())
VirtualTable::erase(tdbb, rpb);
else if (!relation->rel_view_rse)

View File

@ -923,7 +923,7 @@ Jrd::Request* Attachment::findSystemRequest(thread_db* tdbb, USHORT id, Internal
// Msg363 "request depth exceeded. (Recursive definition?)"
}
Request* clone = statement->getRequest(tdbb, n);
Request* clone = statement->getRequest(tdbb, n, true);
if (!(clone->req_flags & (req_active | req_reserved)))
{

View File

@ -25,6 +25,8 @@
#ifndef JRD_ATTACHMENT_H
#define JRD_ATTACHMENT_H
#define DEBUG_LCK_LIST
#include "firebird.h"
// Definition of block types for data allocation in JRD
#include "../include/fb_blk.h"
@ -51,7 +53,6 @@
#include <atomic>
#define DEBUG_LCK_LIST
namespace EDS {
class Connection;
@ -91,7 +92,7 @@ namespace Jrd
class jrd_rel;
class jrd_prc;
class Trigger;
class TrigVector;
class Triggers;
class Function;
class Statement;
class ProfilerManager;

118
src/jrd/CharSetContainer.h Normal file
View File

@ -0,0 +1,118 @@
/*
* PROGRAM: JRD Access Method
* MODULE: CharSetContainer.h
* DESCRIPTION: Container for character set and it's collations
*
* 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): ______________________________________.
*
* Alex Peshkoff <peshkoff@mail.ru>
*/
#ifndef JRD_CHARSETCONTAINER_H
#define JRD_CHARSETCONTAINER_H
#include "../jrd/HazardPtr.h"
#include "../jrd/Collation.h"
#include "../common/classes/alloc.h"
struct SubtypeInfo;
namespace Jrd {
class CharSetContainer : public Firebird::PermanentStorage
{
public:
CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInfo* info);
void destroy()
{
cs->destroy();
}
static void destroy(CharSetContainer* container)
{
container->destroy();
delete container;
}
static CharSetContainer* create(thread_db* tdbb, MetaId id, CacheObject::Flag flags);
static Lock* getLock(MemoryPool& p, thread_db* tdbb);
CharSet* getCharSet()
{
return cs;
}
CsConvert lookupConverter(thread_db* tdbb, CHARSET_ID to_cs);
static CharSetContainer* lookupCharset(thread_db* tdbb, USHORT ttype);
static Lock* createCollationLock(thread_db* tdbb, USHORT ttype, void* object = NULL);
bool hasData() const
{
return cs != nullptr;
}
const char* c_name() const
{
return cs->getName();
}
private:
static bool lookupInternalCharSet(USHORT id, SubtypeInfo* info);
private:
CharSet* cs;
};
class CharSetVers final : public CacheObject
{
public:
CharSetVers(CharSetContainer* parent)
: perm(parent), charset_collations(perm->getPool())
{ }
const char* c_name() const override
{
return perm->c_name();
}
void release(thread_db* tdbb)
{
for (auto coll : charset_collations)
{
if (coll)
coll->release(tdbb);
}
}
static void destroy(CharSetVers* csv);
static CharSetVers* create(thread_db* tdbb, MemoryPool& p, MetaId id, CacheObject::Flag flags);
Collation* lookupCollation(thread_db* tdbb, MetaId id);
//void unloadCollation(thread_db* tdbb, USHORT tt_id);
private:
CharSetContainer* perm;
Firebird::HalfStaticArray<Collation*, 16> charset_collations;
};
} // namespace Jrd
#endif // JRD_CHARSETCONTAINER_H

View File

@ -39,13 +39,13 @@ ConfigTable::ConfigTable(MemoryPool& pool, const Config* conf) :
RecordBuffer* ConfigTable::getRecords(thread_db* tdbb, jrd_rel* relation)
{
fb_assert(relation);
fb_assert(relation->rel_id == rel_config);
fb_assert(relation->getId() == rel_config);
RecordBuffer* recordBuffer = getData(relation);
if (recordBuffer)
return recordBuffer;
recordBuffer = allocBuffer(tdbb, *tdbb->getDefaultPool(), relation->rel_id);
recordBuffer = allocBuffer(tdbb, *tdbb->getDefaultPool(), relation->getId());
// Check privileges to see RDB$CONFIG
const Attachment* att = tdbb->getAttachment();

View File

@ -93,6 +93,7 @@ class GarbageCollector;
class CryptoManager;
class KeywordsMap;
class MetadataCache;
class ExtEngineManager;
// allocator for keywords table
class KeywordsMapAllocator

View File

@ -278,7 +278,7 @@ RecordBuffer* DbCreatorsList::makeBuffer(thread_db* tdbb)
RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation)
{
fb_assert(relation);
fb_assert(relation->rel_id == rel_sec_db_creators);
fb_assert(relation->getId() == rel_sec_db_creators);
RecordBuffer* buffer = getData(relation);
if (buffer)

View File

@ -910,7 +910,7 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, Request* request, unsig
EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine);
const Nullable<bool>& ssDefiner = trg->ssDefiner.specified ? trg->ssDefiner :
(trg->relation && trg->relation->rel_ss_definer.specified ? trg->relation->rel_ss_definer : Nullable<bool>() );
const MetaString& userName = ssDefiner.specified && ssDefiner.value ? trg->relation->rel_owner_name.c_str() : "";
const MetaString& userName = ssDefiner.specified && ssDefiner.value ? trg->relation->rel_perm->rel_owner_name.c_str() : "";
ContextManager<IExternalTrigger> ctxManager(tdbb, attInfo, trigger,
CallerName(obj_trigger, trg->name, userName));
@ -1598,7 +1598,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
if (relation)
{
metadata->triggerTable = relation->rel_name;
metadata->triggerTable = relation->getName();
MsgMetadata* fieldsMsg = FB_NEW MsgMetadata;
metadata->triggerFields = fieldsMsg;

View File

@ -68,7 +68,7 @@ Function* Function::lookup(thread_db* tdbb, USHORT id, bool return_deleted, bool
Function* function = dbb->dbb_mdc->getFunction(tdbb, id, noscan);
if (function && function->getId() == id &&
!(function->flags & Routine::FLAG_CLEARED) &&
// !(function->flags & Routine::FLAG_CLEARED) &&
!(function->flags & Routine::FLAG_BEING_SCANNED) &&
((function->flags & Routine::FLAG_SCANNED) || noscan) &&
!(function->flags & Routine::FLAG_BEING_ALTERED) &&
@ -80,7 +80,6 @@ Function* Function::lookup(thread_db* tdbb, USHORT id, bool return_deleted, bool
}
check_function = function;
check_function->sharedCheckLock(tdbb);
}
// We need to look up the function in RDB$FUNCTIONS
@ -117,7 +116,7 @@ Function* Function::lookup(thread_db* tdbb, const QualifiedName& name, bool nosc
// See if we already know the function by name
Function* function = dbb->dbb_mdc->lookupFunction(tdbb, name, noscan ? 0 : Routine::FLAG_SCANNED,
Routine::FLAG_OBSOLETE | Routine::FLAG_CLEARED | Routine::FLAG_BEING_SCANNED | Routine::FLAG_BEING_ALTERED);
Routine::FLAG_OBSOLETE | /*Routine::FLAG_CLEARED |*/ Routine::FLAG_BEING_SCANNED | Routine::FLAG_BEING_ALTERED);
if (function)
{
@ -166,20 +165,39 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
return nullptr;
}
Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
Lock* Function::getLock(MemoryPool& p, thread_db* tdbb)
{
return FB_NEW_RPT(p, 0) Lock(tdbb, sizeof(SLONG), LCK_fun_exist, nullptr, blockingAst);
}
int Function::blockingAst(void* ast_object)
{
RoutinePermanent* const routine = static_cast<RoutinePermanent*>(ast_object);
try
{
Database* const dbb = function->existenceLock->lck_dbb;
AsyncContextHolder tdbb(dbb, FB_FUNCTION, function->existenceLock);
LCK_release(tdbb, function->existenceLock);
function->flags |= Routine::FLAG_OBSOLETE;
}
catch (const Firebird::Exception&)
{} // no-op
return 0;
}
Function* Function::create(thread_db* tdbb, MemoryPool& pool, MetaId id, CacheObject::Flag flags)
{
Jrd::Attachment* attachment = tdbb->getAttachment();
jrd_tra* sysTransaction = attachment->getSysTransaction();
Database* const dbb = tdbb->getDatabase();
Function* function = FB_NEW_POOL(*dbb->dbb_permanent) Function(*dbb->dbb_permanent, id);
/*
if (!function->existenceLock)
{
function->existenceLock = FB_NEW_POOL(pool)
ExistenceLock(pool, tdbb, LCK_fun_exist, function->getId(), function.getPointer());
}
*/
RoutinePermanent* perm = MetadataCache::lookupFunction(tdbb, id, flags && CacheFlag::NOSCAN);
fb_assert(perm);
Function* function = FB_NEW_POOL(pool) Function(perm);
try
{
@ -191,15 +209,15 @@ Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_ID EQ id
{
function->setName(QualifiedName(X.RDB$FUNCTION_NAME,
perm->setName(QualifiedName(X.RDB$FUNCTION_NAME,
(X.RDB$PACKAGE_NAME.NULL ? nullptr : X.RDB$PACKAGE_NAME)));
function->owner = X.RDB$OWNER_NAME;
perm->owner = X.RDB$OWNER_NAME;
Nullable<bool> ssDefiner;
if (!X.RDB$SECURITY_CLASS.NULL)
{
function->setSecurityName(X.RDB$SECURITY_CLASS);
perm->setSecurityName(X.RDB$SECURITY_CLASS);
}
else if (!X.RDB$PACKAGE_NAME.NULL)
{
@ -211,7 +229,7 @@ Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
if (!PKG.RDB$SECURITY_CLASS.NULL)
{
function->setSecurityName(PKG.RDB$SECURITY_CLASS);
perm->setSecurityName(PKG.RDB$SECURITY_CLASS);
}
// SQL SECURITY of function must be the same if it's defined in package
@ -230,7 +248,7 @@ Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
}
if (ssDefiner.orElse(false))
function->invoker = attachment->getUserId(function->owner);
function->invoker = attachment->getUserId(perm->owner);
size_t count = 0;
ULONG length = 0;
@ -249,7 +267,7 @@ Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
Y.RDB$PACKAGE_NAME EQUIV NULLIF(function->getName().package.c_str(), '')
SORTED BY Y.RDB$ARGUMENT_POSITION
{
Parameter* parameter = FB_NEW_POOL(function->getPool()) Parameter(function->getPool());
Parameter* parameter = FB_NEW_POOL(pool) Parameter(pool);
if (Y.RDB$ARGUMENT_POSITION != X.RDB$RETURN_ARGUMENT)
{
@ -452,10 +470,10 @@ Function* Function::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
else
{
RefPtr<MsgMetadata> inputMetadata(REF_NO_INCR, createMetadata(function->getInputFields(), false));
function->setInputFormat(createFormat(function->getPool(), inputMetadata, false));
function->setInputFormat(createFormat(pool, inputMetadata, false));
RefPtr<MsgMetadata> outputMetadata(REF_NO_INCR, createMetadata(function->getOutputFields(), false));
function->setOutputFormat(createFormat(function->getPool(), outputMetadata, true));
function->setOutputFormat(createFormat(pool, outputMetadata, true));
function->setImplemented(false);
}

View File

@ -27,6 +27,7 @@
#include "../jrd/val.h"
#include "../dsql/Nodes.h"
#include "../jrd/HazardPtr.h"
#include "../jrd/lck.h"
namespace Jrd
{
@ -38,21 +39,24 @@ namespace Jrd
static const char* const EXCEPTION_MESSAGE;
public:
static Lock* getLock(MemoryPool& p, thread_db* tdbb);
static int blockingAst(void* ast_object);
static Function* lookup(thread_db* tdbb, MetaId id, bool return_deleted, bool noscan, USHORT flags);
static Function* lookup(thread_db* tdbb, const QualifiedName& name, bool noscan);
explicit Function(MemoryPool& p)
: Routine(p),
explicit Function(RoutinePermanent* perm)
: Routine(perm),
fun_entrypoint(NULL),
fun_inputs(0),
fun_return_arg(0),
fun_temp_length(0),
fun_exception_message(p),
fun_exception_message(perm->getPool()),
fun_deterministic(false),
fun_external(NULL)
{
}
/* ????????????????
private:
Function(MemoryPool& p, MetaId id)
: Routine(p, id),
@ -65,10 +69,10 @@ private:
fun_external(NULL)
{
}
*/
public:
static Function* loadMetadata(thread_db* tdbb, MetaId id, bool noscan, USHORT flags);
static Function* create(thread_db* tdbb, MetaId id, CacheObject::Flag flags);
static Function* create(thread_db* tdbb, MemoryPool& pool, MetaId id, CacheObject::Flag flags);
public:
virtual int getObjectType() const

View File

@ -30,6 +30,9 @@
#include "../jrd/HazardPtr.h"
#include "../jrd/jrd.h"
#include "../jrd/Database.h"
#include "../jrd/tra.h"
#include "../jrd/met.h"
using namespace Jrd;
using namespace Firebird;
@ -40,6 +43,33 @@ HazardObject::~HazardObject()
CacheObject* TRAP = nullptr;
// class TransactionNumber
TraNumber TransactionNumber::current(thread_db* tdbb)
{
jrd_tra* tra = tdbb->getTransaction();
return tra ? tra->tra_number : 0;
}
TraNumber TransactionNumber::oldestActive(thread_db* tdbb)
{
return tdbb->getDatabase()->dbb_oldest_active;
}
TraNumber TransactionNumber::next(thread_db* tdbb)
{
return tdbb->getDatabase()->dbb_next_transaction;
}
// class VersionSupport
MdcVersion VersionSupport::next(thread_db* tdbb)
{
return tdbb->getDatabase()->dbb_mdc->nextVersion();
}
bool CacheObject::checkObject(thread_db*, Arg::StatusVector&)
{
return true;

View File

@ -41,6 +41,9 @@
#include <type_traits>
#include "../jrd/tdbb.h"
#include "../jrd/Database.h"
namespace Jrd {
class HazardObject
@ -48,8 +51,6 @@ namespace Jrd {
protected:
void retire()
{
fb_assert(this);
struct Disposer
{
void operator()(HazardObject* ho)
@ -377,6 +378,8 @@ namespace Jrd {
Generation::destroy(currentData.load(std::memory_order_acquire));
}
void clear() { } // NO-op, rely on dtor
private:
atomics::atomic<Generation*> currentData;
};
@ -392,6 +395,695 @@ namespace Jrd {
virtual const char* c_name() const = 0;
};
class ObjectBase : public HazardObject
{
public:
enum ResetType {Recompile, Mark, Commit, Rollback};
typedef SLONG ReturnedId; // enable '-1' as not found
public:
virtual void resetDependentObject(thread_db* tdbb, ResetType rt) = 0;
virtual void eraseObject(thread_db* tdbb) = 0; // erase object
public:
void resetDependentObjects(thread_db* tdbb, TraNumber olderThan);
void addDependentObject(thread_db* tdbb, ObjectBase* dep);
void removeDependentObject(thread_db* tdbb, ObjectBase* dep);
[[noreturn]] void busyError(thread_db* tdbb, MetaId id, const char* name);
};
namespace CacheFlag
{
static const CacheObject::Flag COMMITTED = 0x01;
static const CacheObject::Flag ERASED = 0x02;
static const CacheObject::Flag NOSCAN = 0x04;
static const CacheObject::Flag AUTOCREATE = 0x08;
static const CacheObject::Flag INIT = 0x10;
static const CacheObject::Flag IGNORE_MASK = COMMITTED | ERASED;
}
class VersionSupport
{
public:
static MdcVersion next(thread_db* tdbb);
};
class CachePool
{
public:
static MemoryPool& get(thread_db* tdbb);
/*
Database* dbb = tdbb->getDatabase();
return dbb->dbb_mdc->getPool();
*/
};
template <class OBJ>
class CacheList : public HazardObject
{
public:
CacheList(OBJ* obj, TraNumber currentTrans, CacheObject::Flag fl)
: object(obj), next(nullptr), traNumber(currentTrans), cacheFlags(fl)
{ }
~CacheList()
{
OBJ::destroy(object);
delete next;
}
// find appropriate object in cache
static OBJ* getObject(HazardPtr<CacheList>& listEntry, TraNumber currentTrans, CacheObject::Flag flags)
{
for (; listEntry; listEntry.set(listEntry->next))
{
CacheObject::Flag f(listEntry->cacheFlags.load() & ~(flags & CacheFlag::IGNORE_MASK));
if ((f & CacheFlag::COMMITTED) ||
// committed (i.e. confirmed) objects are freely available
(currentTrans && (listEntry->traNumber == currentTrans)))
// transaction that created an object can always access it
{
if (f & CacheFlag::ERASED)
{
// object does not exist
fb_assert(!listEntry->object);
return nullptr;
}
// required entry found in the list
return listEntry->object;
}
}
return nullptr; // object created (not by us) and not committed yet
}
bool isBusy(TraNumber currentTrans) const
{
return traNumber != currentTrans && !(cacheFlags & CacheFlag::COMMITTED);
}
// add new entry to the list
static bool add(atomics::atomic<CacheList*>& list, CacheList* newVal)
{
HazardPtr<CacheList> oldVal(list);
do
{
if (oldVal && oldVal->isBusy(newVal->traNumber)) // modified in other transaction
return false;
newVal->next.store(oldVal.getPointer(), atomics::memory_order_acquire);
} while (! oldVal.replace2(list, newVal));
return true;
}
// insert newVal in the beginning of a list provided there is still oldVal at the top of the list
static bool replace(atomics::atomic<CacheList*>& list, CacheList* newVal, CacheList* oldVal)
{
if (oldVal && oldVal->isBusy(newVal->traNumber)) // modified in other transaction
return false;
newVal->next.store(oldVal, atomics::memory_order_acquire);
return list.compare_exchange_strong(oldVal, newVal, std::memory_order_release, std::memory_order_acquire);
}
// remove too old objects - they are anyway can't be in use
static TraNumber cleanup(atomics::atomic<CacheList*>& list, const TraNumber oldest)
{
TraNumber rc = 0;
for (HazardPtr<CacheList> entry(list); entry; entry.set(entry->next))
{
if ((entry->cacheFlags & CacheFlag::COMMITTED) && entry->traNumber < oldest)
{
if (entry->cacheFlags.fetch_or(CacheFlag::ERASED) & CacheFlag::ERASED)
break; // someone else also performs cleanup
// split remaining list off
if (entry.replace2(list, nullptr))
{
while (entry && !(entry->cacheFlags.fetch_or(CacheFlag::ERASED) & CacheFlag::ERASED))
{
entry->retire();
OBJ::destroy(entry->object);
entry.set(entry->next);
}
}
break;
}
// store traNumber of last not removed list element
rc = entry->traNumber;
}
return rc; // 0 is returned in a case when list becomes empty
}
// created earlier object is OK and should become visible to the world
void commit(thread_db* tdbb, TraNumber currentTrans, TraNumber nextTrans)
{
fb_assert(cacheFlags == 0);
fb_assert(traNumber == currentTrans);
traNumber = nextTrans;
cacheFlags |= CacheFlag::COMMITTED;
version = VersionSupport::next(tdbb);
}
// created earlier object is bad and should be destroyed
static void rollback(atomics::atomic<CacheList*>& list, const TraNumber currentTran)
{
// Take into an account that no other transaction except current (i.e. object creator)
// can access uncommitted objects, only list entries may be accessed as hazard pointers.
// Therefore rollback can retire such entries at once, a kind of pop() from stack.
HazardPtr<CacheList> entry(list);
while (entry)
{
if (entry->cacheFlags & CacheFlag::COMMITTED)
break;
fb_assert(entry->traNumber == currentTran);
if (entry.replace2(list, entry->next))
{
entry->retire();
OBJ::destroy(entry->object);
entry = list;
}
}
}
void assertCommitted()
{
fb_assert(cacheFlags & CacheFlag::COMMITTED);
}
private:
// object (nill/not nill) & ERASED bit in cacheFlags together control state of cache element
// | ERASED
//----------------------------------|-----------------------------
// object | true | false
//----------------------------------|-----------------------------
// nill | object dropped | cache to be loaded
// not nill | prohibited | cache is actual
OBJ* object;
atomics::atomic<CacheList*> next;
TraNumber traNumber; // when COMMITTED not set - stores transaction that created this list element
// when COMMITTED is set - stores transaction after which older elements are not needed
// traNumber to be changed BEFORE setting COMMITTED
MdcVersion version; // version of metadata cache when object was added
atomics::atomic<CacheObject::Flag> cacheFlags;
};
class TransactionNumber
{
public:
static TraNumber current(thread_db* tdbb);
static TraNumber oldestActive(thread_db* tdbb);
static TraNumber next(thread_db* tdbb);
};
class Lock;
template <class E>
MemoryPool& getObjectPool(thread_db* tdbb, E* ext)
{
return ext->getPool();
}
template <>
MemoryPool& getObjectPool(thread_db* tdbb, NullClass* ext)
{
return CachePool::get(tdbb);
}
template <class OBJ, class EXT>
class CacheElement : public ObjectBase, public EXT
{
typedef CacheList<OBJ> CachedObj;
public:
CacheElement(MemoryPool& p, MetaId id, Lock* lock) :
EXT(p, id, lock), list(nullptr), resetAt(0), myId(id)
{ }
CacheElement() :
EXT(), list(nullptr), resetAt(0), myId(0)
{ }
~CacheElement()
{
delete list.load();
cleanup();
}
OBJ* getObject(thread_db* tdbb, CacheObject::Flag flags = 0)
{
TraNumber cur = TransactionNumber::current(tdbb);
HazardPtr<CachedObj> listEntry(list);
if (!listEntry)
{
OBJ* obj = OBJ::create(tdbb, getObjectPool<EXT>(tdbb, this), myId, 0);
CachedObj* newVal = FB_NEW_POOL(CachePool::get(tdbb)) CachedObj(obj, cur, obj ? 0 : CacheFlag::ERASED);
if (CachedObj::replace(list, newVal, nullptr))
return obj;
delete newVal;
if (obj)
OBJ::destroy(obj);
listEntry.set(list);
fb_assert(listEntry);
}
return CachedObj::getObject(listEntry, cur, flags);
}
bool storeObject(thread_db* tdbb, OBJ* obj, CacheObject::Flag fl = 0)
{
TraNumber oldest = TransactionNumber::oldestActive(tdbb);
TraNumber oldResetAt = resetAt.load(atomics::memory_order_acquire);
if (oldResetAt && oldResetAt < oldest)
setNewResetAt(oldResetAt, CachedObj::cleanup(list, oldest));
TraNumber current = TransactionNumber::current(tdbb);
CachedObj* value = FB_NEW CachedObj(obj, current, fl & CacheFlag::IGNORE_MASK);
bool stored = fl & CacheFlag::INIT ? CachedObj::replace(list, value, nullptr) : CachedObj::add(list, value);
if (stored)
setNewResetAt(oldResetAt, current);
else
delete value;
return stored;
}
void storeObjectWithTimeout(thread_db* tdbb, OBJ* obj, std::function<void()> error);
void commit(thread_db* tdbb)
{
HazardPtr<CachedObj> current(list);
if (current)
current->commit(tdbb, TransactionNumber::current(tdbb), TransactionNumber::next(tdbb));
}
void rollback(thread_db* tdbb)
{
CachedObj::rollback(list, TransactionNumber::current(tdbb));
}
void cleanup()
{
list.load()->assertCommitted();
CachedObj::cleanup(list, MAX_TRA_NUMBER);
}
void resetDependentObject(thread_db* tdbb, ResetType rt) override
{
switch (rt)
{
case ObjectBase::ResetType::Recompile:
{
OBJ* newObj = OBJ::create(tdbb, CachePool::get(tdbb), myId, 0);
if (!storeObject(tdbb, newObj))
{
OBJ::destroy(newObj);
OBJ* oldObj = getObject(tdbb);
busyError(tdbb, myId, oldObj ? oldObj->c_name() : nullptr);
}
}
break;
case ObjectBase::ResetType::Mark:
// used in AST, therefore ignore error when saving empty object
if (storeObject(tdbb, nullptr))
commit(tdbb);
break;
case ObjectBase::ResetType::Commit:
commit(tdbb);
break;
case ObjectBase::ResetType::Rollback:
rollback(tdbb);
break;
}
}
void eraseObject(thread_db* tdbb) override
{
HazardPtr<CachedObj> l(list);
fb_assert(l);
if (!l)
return;
if (!storeObject(tdbb, nullptr, CacheFlag::ERASED))
{
OBJ* oldObj = getObject(tdbb);
busyError(tdbb, myId, oldObj ? oldObj->c_name() : nullptr);
}
}
// Checking it does not protect from something to be added in this element at next cycle!!!
bool hasData() const
{
return list.load(atomics::memory_order_relaxed);
}
private:
void setNewResetAt(TraNumber oldVal, TraNumber newVal)
{
resetAt.compare_exchange_strong(oldVal, newVal,
atomics::memory_order_release, atomics::memory_order_relaxed);
}
private:
atomics::atomic<CachedObj*> list;
atomics::atomic<TraNumber> resetAt;
public:
atomics::atomic<ULONG> flags; // control non-versioned features (like foreign keys)
const MetaId myId;
};
template <class E, class EXT = NullClass, unsigned SUBARRAY_SHIFT = 8>
class CacheVector : public Firebird::PermanentStorage
{
public:
static const unsigned SUBARRAY_SIZE = 1 << SUBARRAY_SHIFT;
static const unsigned SUBARRAY_MASK = SUBARRAY_SIZE - 1;
typedef CacheElement<E, EXT> StoredObject;
typedef atomics::atomic<StoredObject*> SubArrayData;
typedef atomics::atomic<SubArrayData*> ArrayData;
typedef SharedReadVector<ArrayData, 4> Storage;
explicit CacheVector(MemoryPool& pool)
: Firebird::PermanentStorage(pool),
m_objects(getPool())
{}
private:
static FB_SIZE_T getCount(const HazardPtr<typename Storage::Generation>& v)
{
return v->getCount() << SUBARRAY_SHIFT;
}
SubArrayData* getDataPointer(MetaId id) const
{
auto up = m_objects.readAccessor();
if (id >= getCount(up))
return nullptr;
auto sub = up->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
return &sub[id & SUBARRAY_MASK];
}
void grow(FB_SIZE_T reqSize)
{
fb_assert(reqSize > 0);
reqSize = ((reqSize - 1) >> SUBARRAY_SHIFT) + 1;
Firebird::MutexLockGuard g(objectsGrowMutex, FB_FUNCTION);
m_objects.grow(reqSize);
auto wa = m_objects.writeAccessor();
fb_assert(wa->getCapacity() >= reqSize);
while (wa->getCount() < reqSize)
{
SubArrayData* sub = FB_NEW_POOL(getPool()) SubArrayData[SUBARRAY_SIZE];
memset(sub, 0, sizeof(SubArrayData) * SUBARRAY_SIZE);
wa->add()->store(sub, atomics::memory_order_release);
}
}
public:
StoredObject* getData(MetaId id)
{
auto ptr = getDataPointer(id);
return ptr ? *ptr : nullptr;
}
E* getObject(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
{
// In theory that should be endless cycle - object may arrive/disappear again and again.
// But in order to faster find devel problems we run it very limited number of times.
#ifdef DEV_BUILD
for (int i = 0; i < 2; ++i)
#else
for (;;)
#endif
{
auto ptr = getDataPointer(id);
if (ptr)
{
HazardPtr<StoredObject> data(*ptr);
if (data)
{
auto rc = data->getObject(tdbb, flags);
if (rc)
return rc;
}
}
if (!(flags & CacheFlag::AUTOCREATE))
return nullptr;
auto val = E::create(tdbb, getPool(), id, flags);
if (!val)
(Firebird::Arg::Gds(isc_random) << "Object create failed").raise();
if (storeObject(tdbb, id, val))
return val;
E::destroy(val);
}
#ifdef DEV_BUILD
(Firebird::Arg::Gds(isc_random) << "Object suddenly disappeared").raise();
#endif
}
StoredObject* storeObject(thread_db* tdbb, MetaId id, E* const val)
{
if (id >= getCount())
grow(id + 1);
auto ptr = getDataPointer(id);
fb_assert(ptr);
HazardPtr<StoredObject> data(*ptr);
if (!data)
{
StoredObject* newData = FB_NEW_POOL(getPool()) StoredObject(getPool(), id, E::getLock(getPool(), tdbb));
if (!data.replace2(*ptr, newData))
delete newData;
else
data.set(*ptr);
}
if (!data->storeObject(tdbb, val))
data.clear();
return data.getPointer();
}
StoredObject* lookup(thread_db* tdbb, std::function<bool(E* val)> cmp, MetaId* foundId = nullptr) const
{
auto a = m_objects.readAccessor();
for (FB_SIZE_T i = 0; i < a->getCount(); ++i)
{
SubArrayData* const sub = a->value(i).load(atomics::memory_order_relaxed);
if (!sub)
continue;
for (SubArrayData* end = &sub[SUBARRAY_SIZE]; sub < end--;)
{
StoredObject* ptr = end->load(atomics::memory_order_relaxed);
if (!ptr)
continue;
E* val = ptr->getObject(tdbb);
if (val && cmp(val))
{
if (foundId)
*foundId = (i << SUBARRAY_SHIFT) + (end - sub);
return ptr;
}
}
}
return nullptr;
}
~CacheVector()
{
cleanup();
}
void cleanup()
{
auto a = m_objects.writeAccessor();
for (FB_SIZE_T i = 0; i < a->getCount(); ++i)
{
SubArrayData* const sub = a->value(i).load(atomics::memory_order_relaxed);
if (!sub)
continue;
for (SubArrayData* end = &sub[SUBARRAY_SIZE]; sub < end--;)
delete *end; // no need using release here in CacheVector's dtor
delete[] sub;
}
m_objects.clear();
//delete a;
}
FB_SIZE_T getCount() const
{
return m_objects.readAccessor()->getCount() << SUBARRAY_SHIFT;
}
bool replace2(MetaId id, HazardPtr<E>& oldVal, E* const newVal)
{
if (id >= getCount())
grow(id + 1);
auto a = m_objects.readAccessor();
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
sub = &sub[id & SUBARRAY_MASK];
return oldVal.replace2(sub, newVal);
}
bool clear(MetaId id)
{
if (id >= getCount())
return false;
auto a = m_objects.readAccessor();
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
sub = &sub[id & SUBARRAY_MASK];
sub->store(nullptr, atomics::memory_order_release);
return true;
}
bool load(MetaId id, HazardPtr<E>& val) const
{
auto a = m_objects.readAccessor();
if (id < getCount(a))
{
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
if (sub)
{
val.set(sub[id & SUBARRAY_MASK]);
if (val && val->hasData())
return true;
}
}
return false;
}
HazardPtr<E> load(MetaId id) const
{
HazardPtr<E> val;
if (!load(id, val))
val.clear();
return val;
}
HazardPtr<typename Storage::Generation> readAccessor() const
{
return m_objects.readAccessor();
}
class Iterator
{
public:
StoredObject* operator*()
{
return get();
}
/* StoredObject& operator->()
{
return get();
}
*/
Iterator& operator++()
{
index = locateData(index + 1);
return *this;
}
bool operator==(const Iterator& itr) const
{
fb_assert(data == itr.data);
return index == itr.index;
}
bool operator!=(const Iterator& itr) const
{
fb_assert(data == itr.data);
return index != itr.index;
}
private:
void* operator new(size_t);
void* operator new[](size_t);
public:
enum class Location {Begin, End};
Iterator(const CacheVector* v, Location loc)
: data(v),
index(loc == Location::Begin ? locateData(0) : data->getCount())
{ }
StoredObject* get()
{
StoredObject* ptr = data->getData(index);
fb_assert(ptr);
return ptr;
}
FB_SIZE_T locateData(FB_SIZE_T i)
{
while (!data->getData(i))
++i;
return i;
}
private:
const CacheVector* data;
FB_SIZE_T index; // should be able to store MAX_METAID + 1 value
};
Iterator begin() const
{
return Iterator(this, Iterator::Location::Begin);
}
Iterator end() const
{
return Iterator(this, Iterator::Location::End);
}
private:
Storage m_objects;
Firebird::Mutex objectsGrowMutex;
};
} // namespace Jrd
#endif // JRD_HAZARDPTR_H

View File

@ -65,6 +65,48 @@ private:
static Firebird::MemoryStats m_stats;
};
class InitPool
{
public:
explicit InitPool(MemoryPool&)
{
m_pool = InitCDS::createPool();
m_pool->setStatsGroup(m_stats);
}
~InitPool()
{
// m_pool will be deleted by InitCDS dtor after cds termination
// some memory could still be not freed until that moment
#ifdef DEBUG_CDS_MEMORY
char str[256];
sprintf(str, "DHP pool stats:\n"
" usage = %llu\n"
" mapping = %llu\n"
" max usage = %llu\n"
" max mapping = %llu\n"
"\n",
m_stats.getCurrentUsage(),
m_stats.getCurrentMapping(),
m_stats.getMaximumUsage(),
m_stats.getMaximumMapping()
);
gds__log(str);
#endif
}
void* alloc(size_t size)
{
return m_pool->allocate(size ALLOC_ARGS);
}
private:
MemoryPool* m_pool;
Firebird::MemoryStats m_stats;
};
} // namespace Jrd
#endif // FB_INIT_CDSLIB_H

View File

@ -32,13 +32,13 @@ using namespace Firebird;
RecordBuffer* KeywordsTable::getRecords(thread_db* tdbb, jrd_rel* relation)
{
fb_assert(relation);
fb_assert(relation->rel_id == rel_keywords);
fb_assert(relation->getId() == rel_keywords);
auto recordBuffer = getData(relation);
if (recordBuffer)
return recordBuffer;
recordBuffer = allocBuffer(tdbb, *tdbb->getDefaultPool(), relation->rel_id);
recordBuffer = allocBuffer(tdbb, *tdbb->getDefaultPool(), relation->getId());
const auto record = recordBuffer->getTempRecord();

View File

@ -1663,7 +1663,7 @@ RecordBuffer* MappingList::makeBuffer(thread_db* tdbb)
RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation)
{
fb_assert(relation);
fb_assert(relation->rel_id == rel_global_auth_mapping);
fb_assert(relation->getId() == rel_global_auth_mapping);
RecordBuffer* buffer = getData(relation);
if (buffer)

View File

@ -119,9 +119,9 @@ bool MonitoringTableScan::retrieveRecord(thread_db* tdbb, jrd_rel* relation,
if (!snapshot->getData(relation)->fetch(position, record))
return false;
if (relation->rel_id == rel_mon_attachments || relation->rel_id == rel_mon_statements)
if (relation->getId() == rel_mon_attachments || relation->getId() == rel_mon_statements)
{
const USHORT fieldId = (relation->rel_id == rel_mon_attachments) ?
const USHORT fieldId = (relation->getId() == rel_mon_attachments) ?
(USHORT) f_mon_att_idle_timer : (USHORT) f_mon_stmt_timer;
dsc desc;
@ -133,7 +133,7 @@ bool MonitoringTableScan::retrieveRecord(thread_db* tdbb, jrd_rel* relation,
ISC_TIMESTAMP_TZ* ts = reinterpret_cast<ISC_TIMESTAMP_TZ*> (desc.dsc_address);
ts->utc_timestamp = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
if (relation->rel_id == rel_mon_attachments)
if (relation->getId() == rel_mon_attachments)
{
const SINT64 currClock = fb_utils::query_performance_counter() / fb_utils::query_performance_frequency();
NoThrowTimeStamp::add10msec(&ts->utc_timestamp, clock - currClock, ISC_TIME_SECONDS_PRECISION);
@ -630,7 +630,7 @@ RecordBuffer* SnapshotData::getData(const jrd_rel* relation) const
{
fb_assert(relation);
return getData(relation->rel_id);
return getData(relation->getId());
}
@ -650,14 +650,13 @@ RecordBuffer* SnapshotData::allocBuffer(thread_db* tdbb, MemoryPool& pool, int r
{
jrd_rel* relation = MetadataCache::lookup_relation_id(tdbb, rel_id, false);
fb_assert(relation);
MET_scan_relation(tdbb, relation);
fb_assert(relation->isVirtual());
const Format* const format = MET_current(tdbb, relation);
fb_assert(format);
RecordBuffer* const buffer = FB_NEW_POOL(pool) RecordBuffer(pool, format);
const RelationData data = {relation->rel_id, buffer};
const RelationData data = {relation->getId(), buffer};
m_snapshot.add(data);
return buffer;
@ -708,11 +707,11 @@ void SnapshotData::putField(thread_db* tdbb, Record* record, const DumpField& fi
SLONG rel_id;
memcpy(&rel_id, field.data, field.length);
jrd_rel* relation = MetadataCache::lookup_relation_id(tdbb, rel_id, false);
if (!relation || relation->rel_name.isEmpty())
RelationPermanent* relation = MetadataCache::lookupRelation(tdbb, rel_id, false);
if (!relation || relation->getName().isEmpty())
return;
const MetaName& name = relation->rel_name;
const MetaName& name = relation->getName();
dsc from_desc;
from_desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str());
MOV_move(tdbb, &from_desc, &to_desc);

View File

@ -572,7 +572,7 @@ RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch*
// Find relation either by id or by name
AutoPtr<string> aliasString;
MetaName name;
CacheElement<jrd_rel>* rel = nullptr;
CachedRelation* rel = nullptr;
switch (blrOp)
{
@ -656,7 +656,7 @@ string RelationSourceNode::internalPrint(NodePrinter& printer) const
NODE_PRINT(printer, alias);
NODE_PRINT(printer, context);
if (relation.isSet())
printer.print("rel_name", relation.get(JRD_get_thread_data(), printer.resources)->rel_name);
printer.print("rel_name", relation(JRD_get_thread_data())->getName());
return "RelationSourceNode";
}
@ -734,13 +734,13 @@ RecordSourceNode* RelationSourceNode::pass1(thread_db* tdbb, CompilerScratch* cs
if (relation.isSet() && !csb->csb_implicit_cursor)
{
const SLONG ssRelationId = tail->csb_view.isSet() ?
tail->csb_view.get(tdbb, csb->csb_resources)->rel_id : view.isSet() ?
view.get(tdbb, csb->csb_resources)->rel_id : csb->csb_view.isSet() ?
csb->csb_view.get(tdbb, csb->csb_resources)->rel_id : 0;
tail->csb_view()->getId() : view.isSet() ?
view()->getId() : csb->csb_view.isSet() ?
csb->csb_view()->getId() : 0;
const jrd_rel* r = relation.get(tdbb, csb->csb_resources);
const RelationPermanent* r = relation();
CMP_post_access(tdbb, csb, r->rel_security_name, ssRelationId,
SCL_select, obj_relations, r->rel_name);
SCL_select, obj_relations, r->getName());
}
return this;
@ -757,11 +757,11 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
// prepare to check protection of relation when a field in the stream of the
// relation is accessed.
CachedResource<jrd_rel> const parentView = csb->csb_view;
Rsc::Rel const parentView = csb->csb_view;
const StreamType viewStream = csb->csb_view_stream;
CachedResource<jrd_rel> relationView = relation;
//csb->csb_resources.postResource(tdbb, Resource::rsc_relation, relationView, relationView->rel_id);
Rsc::Rel relationView = relation;
//csb->csb_resources.postResource(tdbb, Resource::rsc_relation, relationView, relationView->getId());
view = parentView;
CompilerScratch::csb_repeat* const element = CMP_csb_element(csb, stream);
@ -772,7 +772,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
if (parentView.isSet())
{
const ViewContexts& ctx = parentView.get(tdbb, csb->csb_resources)->rel_view_contexts;
const ViewContexts& ctx = parentView(tdbb)->rel_view_contexts;
const USHORT key = context;
FB_SIZE_T pos;
@ -785,7 +785,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
// check for a view - if not, nothing more to do
RseNode* viewRse = relationView.get(tdbb, csb->csb_resources)->rel_view_rse;
RseNode* viewRse = relationView(tdbb)->rel_view_rse;
if (!viewRse)
return;
@ -796,7 +796,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
AutoSetRestore<CachedResource<jrd_rel>> autoView(&csb->csb_view, relationView);
AutoSetRestore<Rsc::Rel> autoView(&csb->csb_view, relationView);
AutoSetRestore<StreamType> autoViewStream(&csb->csb_view_stream, stream);
// We don't expand the view in two cases:
@ -906,10 +906,10 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
SET_TDBB(tdbb);
const auto blrStartPos = csb->csb_blr_reader.getPos();
jrd_prc* procedure = nullptr;
AutoPtr<string> aliasString;
QualifiedName name;
CacheElement<jrd_prc>* proc = nullptr;
CacheElement<jrd_prc, RoutinePermanent>* proc = nullptr;
SubRoutine<jrd_prc> nodeProc;
switch (blrOp)
{
@ -953,43 +953,45 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
{
DeclareSubProcNode* declareNode;
for (auto curCsb = csb; curCsb && !procedure; curCsb = curCsb->mainCsb)
for (auto curCsb = csb; curCsb; curCsb = curCsb->mainCsb)
{
if (curCsb->subProcedures.get(name.identifier, declareNode))
procedure = declareNode->routine;
{
nodeProc = declareNode->routine;
break;
}
}
}
else
{
HazardPtr<jrd_prc> proc = MetadataCache::lookup_procedure(tdbb, name, false);
if (proc)
procedure = csb->csb_resources.registerResource(tdbb, Resource::rsc_procedure, proc, proc->getId());
}
proc = MetadataCache::lookupProcedure(tdbb, name);
break;
default:
fb_assert(false);
}
if (proc)
nodeProc = csb->csb_resources->procedures.registerResource(proc);
jrd_prc* procedure = nodeProc(tdbb);
if (!procedure)
PAR_error(csb, Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()));
else
if (procedure->isImplemented() && !procedure->isDefined())
{
if (procedure->isImplemented() && !procedure->isDefined())
if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator))
{
if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator))
{
PAR_warning(
Arg::Warning(isc_prcnotdef) << Arg::Str(name.toString()) <<
Arg::Warning(isc_modnotfound));
}
else
{
csb->csb_blr_reader.setPos(blrStartPos);
PAR_error(csb,
Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()) <<
Arg::Gds(isc_modnotfound));
}
PAR_warning(
Arg::Warning(isc_prcnotdef) << Arg::Str(name.toString()) <<
Arg::Warning(isc_modnotfound));
}
else
{
csb->csb_blr_reader.setPos(blrStartPos);
PAR_error(csb,
Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()) <<
Arg::Gds(isc_modnotfound));
}
}
@ -1006,9 +1008,8 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
ProcedureSourceNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) ProcedureSourceNode(
*tdbb->getDefaultPool());
node->procedure = csb->csb_resources.procedures->registerResource(tdbb, proc);
node->isSubRoutine = procedure->isSubRoutine();
node->procedureId = node->isSubRoutine ? 0 : procedure->getId();
node->procedure = nodeProc;
node->procedureId = nodeProc()->getId();
if (aliasString)
node->alias = *aliasString;
@ -1017,7 +1018,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
{
node->stream = PAR_context(csb, &node->context);
csb->csb_rpt[node->stream].csb_procedure = procedure;
csb->csb_rpt[node->stream].csb_procedure = nodeProc;
csb->csb_rpt[node->stream].csb_alias = aliasString.release();
PAR_procedure_parms(tdbb, csb, procedure, node->in_msg.getAddress(),
@ -1171,22 +1172,24 @@ ProcedureSourceNode* ProcedureSourceNode::copy(thread_db* tdbb, NodeCopier& copi
if (!copier.remap)
BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
ProcedureSourceNode* newSource = FB_NEW_POOL(*tdbb->getDefaultPool()) ProcedureSourceNode(
*tdbb->getDefaultPool());
ProcedureSourceNode* newSource = FB_NEW_POOL(*tdbb->getDefaultPool())
ProcedureSourceNode(*tdbb->getDefaultPool());
if (isSubRoutine)
// is it really needed with new MDC ?????????????????
if (procedure.isSubRoutine())
newSource->procedure = procedure;
else
{
auto proc = MetadataCache::lookup_procedure_id(tdbb, procedureId, false, false, 0);
newSource->procedure = copier.csb->csb_resources.registerResource(tdbb, Resource::rsc_procedure, proc, proc->getId());
if (!newSource->procedure)
auto proc = MetadataCache::lookupProcedure(tdbb, procedureId);
if (!proc)
{
string name;
name.printf("id %d", procedureId);
delete newSource;
ERR_post(Arg::Gds(isc_prcnotdef) << name);
}
newSource->procedure = copier.csb->csb_resources->procedures.registerResource(proc);
}
// dimitr: See the appropriate code and comment in NodeCopier (in nod_argument).
@ -1203,7 +1206,6 @@ ProcedureSourceNode* ProcedureSourceNode::copy(thread_db* tdbb, NodeCopier& copi
newSource->stream = copier.csb->nextStream();
copier.remap[stream] = newSource->stream;
newSource->context = context;
newSource->isSubRoutine = isSubRoutine;
newSource->procedureId = procedureId;
newSource->view = view;
@ -1236,13 +1238,10 @@ void ProcedureSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, Rse
pass1(tdbb, csb);
if (!isSubRoutine)
{
if (!procedure.isSubRoutine())
CMP_post_procedure_access(tdbb, csb, procedure);
csb->csb_resources.postResource(tdbb, Resource::rsc_procedure, procedure, procedureId);
}
jrd_rel* const parentView = csb->csb_view;
Rsc::Rel const parentView = csb->csb_view;
const StreamType viewStream = csb->csb_view_stream;
view = parentView;
@ -1254,7 +1253,7 @@ void ProcedureSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, Rse
if (parentView)
{
const ViewContexts& ctx = parentView->rel_view_contexts;
const ViewContexts& ctx = parentView(tdbb)->rel_view_contexts;
const USHORT key = context;
FB_SIZE_T pos;
@ -1578,7 +1577,7 @@ void AggregateSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, Rse
pass1(tdbb, csb);
jrd_rel* const parentView = csb->csb_view;
Rsc::Rel const parentView = csb->csb_view;
const StreamType viewStream = csb->csb_view_stream;
CompilerScratch::csb_repeat* const element = CMP_csb_element(csb, stream);
@ -1882,7 +1881,7 @@ void UnionSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode
doPass1(tdbb, csb, ptr2->getAddress());
}
jrd_rel* const parentView = csb->csb_view;
Rsc::Rel const parentView = csb->csb_view;
const StreamType viewStream = csb->csb_view_stream;
CompilerScratch::csb_repeat* const element = CMP_csb_element(csb, stream);
@ -2282,7 +2281,7 @@ void WindowSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNod
pass1(tdbb, csb);
jrd_rel* const parentView = csb->csb_view;
Rsc::Rel const parentView = csb->csb_view;
const StreamType viewStream = csb->csb_view_stream;
for (ObjectsArray<Window>::iterator window = windows.begin();
@ -2429,14 +2428,14 @@ string RseNode::internalPrint(NodePrinter& printer) const
bool RseNode::dsqlAggregateFinder(AggregateFinder& visitor)
{
AutoSetRestore<USHORT> autoValidateExpr(&visitor.currentLevel, visitor.currentLevel + 1);
return visitor.visit(dsqlStreams) | visitor.visit(dsqlWhere) | visitor.visit(dsqlSelectList);
return visitor.visit(dsqlStreams) || visitor.visit(dsqlWhere) || visitor.visit(dsqlSelectList);
}
bool RseNode::dsqlAggregate2Finder(Aggregate2Finder& visitor)
{
AutoSetRestore<bool> autoCurrentScopeLevelEqual(&visitor.currentScopeLevelEqual, false);
// Pass dsqlWhere, dsqlSelectList and dsqlStreams.
return visitor.visit(dsqlWhere) | visitor.visit(dsqlSelectList) | visitor.visit(dsqlStreams);
return visitor.visit(dsqlWhere) || visitor.visit(dsqlSelectList) || visitor.visit(dsqlStreams);
}
bool RseNode::dsqlInvalidReferenceFinder(InvalidReferenceFinder& visitor)
@ -2453,7 +2452,7 @@ bool RseNode::dsqlSubSelectFinder(SubSelectFinder& visitor)
bool RseNode::dsqlFieldFinder(FieldFinder& visitor)
{
// Pass dsqlWhere and dsqlSelectList and dsqlStreams.
return visitor.visit(dsqlWhere) | visitor.visit(dsqlSelectList) | visitor.visit(dsqlStreams);
return visitor.visit(dsqlWhere) || visitor.visit(dsqlSelectList) || visitor.visit(dsqlStreams);
}
RseNode* RseNode::dsqlFieldRemapper(FieldRemapper& visitor)
@ -3020,8 +3019,8 @@ void RseNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
if (rse_plan)
{
planSet(csb, rse_plan);
planCheck(csb);
planSet(tdbb, csb, rse_plan);
planCheck(tdbb, csb);
}
csb->csb_current_nodes.pop();
@ -3093,7 +3092,7 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr
// Check that all streams in the RseNode have a plan specified for them.
// If they are not, there are streams in the RseNode which were not mentioned in the plan.
void RseNode::planCheck(const CompilerScratch* csb) const
void RseNode::planCheck(thread_db* tdbb, const CompilerScratch* csb) const
{
// if any streams are not marked with a plan, give an error
@ -3109,26 +3108,27 @@ void RseNode::planCheck(const CompilerScratch* csb) const
if (!csb->csb_rpt[stream].csb_plan)
{
const auto name = relation ? relation->rel_name :
procedure ? procedure->getName().toString() : "";
const auto name = relation ? relation()->getName() :
procedure ? procedure(tdbb)->getName().toString() : "";
ERR_post(Arg::Gds(isc_no_stream_plan) << Arg::Str(name));
}
}
else if (const auto rse = nodeAs<RseNode>(node))
rse->planCheck(csb);
rse->planCheck(tdbb, csb);
}
}
// Go through the streams in the plan, find the corresponding streams in the RseNode and store the
// plan for that stream. Do it once and only once to make sure there is a one-to-one correspondence
// between streams in the query and streams in the plan.
void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
void RseNode::planSet(thread_db* tdbb, CompilerScratch* csb, PlanNode* plan)
{
if (plan->type == PlanNode::TYPE_JOIN)
{
for (auto planNode : plan->subNodes)
planSet(csb, planNode);
planSet(tdbb, csb, planNode);
}
if (plan->type != PlanNode::TYPE_RETRIEVE)
@ -3141,35 +3141,35 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
string planAlias;
jrd_rel* planRelation = nullptr;
RelationPermanent* planRelation = nullptr;
if (const auto relationNode = nodeAs<RelationSourceNode>(plan->recordSourceNode))
{
planRelation = relationNode->relation;
planRelation = relationNode->relation();
planAlias = relationNode->alias;
}
jrd_prc* planProcedure = nullptr;
RoutinePermanent* planProcedure = nullptr;
if (const auto procedureNode = nodeAs<ProcedureSourceNode>(plan->recordSourceNode))
{
planProcedure = procedureNode->procedure;
planProcedure = procedureNode->procedure();
planAlias = procedureNode->alias;
}
fb_assert(planRelation || planProcedure);
const auto name = planRelation ? planRelation->rel_name :
const auto name = planRelation ? planRelation->getName() :
planProcedure ? planProcedure->getName().toString() : "";
// If the plan references a view, find the real base relation
// we are interested in by searching the view map
StreamType* map = nullptr;
jrd_rel* viewRelation = nullptr;
jrd_prc* viewProcedure = nullptr;
RelationPermanent* viewRelation = nullptr;
RoutinePermanent* viewProcedure = nullptr;
if (tail->csb_map)
{
auto tailName = tail->csb_relation ? tail->csb_relation->rel_name :
tail->csb_procedure ? tail->csb_procedure->getName().toString() : "";
auto tailName = tail->csb_relation ? tail->csb_relation()->getName() :
tail->csb_procedure ? tail->csb_procedure()->getName().toString() : "";
// If the user has specified an alias, skip past it to find the alias
// for the base table (if multiple aliases are specified)
@ -3194,15 +3194,15 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
{
map = mapBase;
tail = &csb->csb_rpt[*map];
viewRelation = tail->csb_relation;
viewProcedure = tail->csb_procedure;
viewRelation = tail->csb_relation();
viewProcedure = tail->csb_procedure();
// If the plan references the view itself, make sure that
// If the plan references the view itself, make sure that
// the view is on a single table. If it is, fix up the plan
// to point to the base relation.
if ((viewRelation && planRelation &&
viewRelation->rel_id == planRelation->rel_id) ||
viewRelation->getId() == planRelation->getId()) ||
(viewProcedure && planProcedure &&
viewProcedure->getId() == planProcedure->getId()))
{
@ -3237,11 +3237,11 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
for (duplicateMap++; *duplicateMap; ++duplicateMap)
{
const auto duplicateTail = &csb->csb_rpt[*duplicateMap];
const auto relation = duplicateTail->csb_relation;
const auto procedure = duplicateTail->csb_procedure;
const auto relation = duplicateTail->csb_relation();
const auto procedure = duplicateTail->csb_procedure();
if ((relation && planRelation &&
relation->rel_id == planRelation->rel_id) ||
relation->getId() == planRelation->getId()) ||
(procedure && planProcedure &&
procedure->getId() == planProcedure->getId()))
{
@ -3253,7 +3253,7 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
}
else
{
duplicateName = relation ? relation->rel_name :
duplicateName = relation ? relation->getName() :
procedure ? procedure->getName().toString() : "";
map = duplicateMap;
tail = duplicateTail;
@ -3271,8 +3271,8 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
{
tail = &csb->csb_rpt[*map];
tailName = tail->csb_relation ? tail->csb_relation->rel_name :
tail->csb_procedure ? tail->csb_procedure->getName().toString() : "";
tailName = tail->csb_relation ? tail->csb_relation()->getName() :
tail->csb_procedure ? tail->csb_procedure()->getName().toString() : "";
// Match the user-supplied alias with the alias supplied
// with the view definition. Failing that, try the base
@ -3319,9 +3319,9 @@ void RseNode::planSet(CompilerScratch* csb, PlanNode* plan)
}
if ((tail->csb_relation && planRelation &&
tail->csb_relation->rel_id != planRelation->rel_id && !viewRelation) ||
tail->csb_relation()->getId() != planRelation->getId() && !viewRelation) ||
(tail->csb_procedure && planProcedure &&
tail->csb_procedure->getId() != planProcedure->getId() && !viewProcedure))
tail->csb_procedure()->getId() != planProcedure->getId() && !viewProcedure))
{
// table or procedure %s is referenced in the plan but not the from list
ERR_post(Arg::Gds(isc_stream_not_found) << Arg::Str(name));

View File

@ -416,10 +416,10 @@ public:
public:
MetaName dsqlName;
Firebird::string alias; // SQL alias for the relation
CachedResource<jrd_rel> relation;
Rsc::Rel relation;
private:
CachedResource<jrd_rel> view; // parent view for posting access
Rsc::Rel view; // parent view for posting access
public:
SSHORT context; // user-specified context number for the relation reference
@ -433,14 +433,11 @@ public:
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_PROCEDURE>(pool),
dsqlName(pool, aDsqlName),
alias(pool),
procedure(NULL),
sourceList(NULL),
targetList(NULL),
in_msg(NULL),
view(NULL),
procedureId(0),
context(0),
isSubRoutine(false)
context(0)
{
}
@ -508,17 +505,16 @@ public:
cache management policies yet, so I leave it for the other day.
***/
jrd_prc* procedure;
SubRoutine<jrd_prc> procedure;
NestConst<ValueListNode> sourceList;
NestConst<ValueListNode> targetList;
private:
NestConst<MessageNode> in_msg;
jrd_rel* view;
Rsc::Rel view;
USHORT procedureId;
SSHORT context;
bool isSubRoutine;
};
class AggregateSourceNode final : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_AGGREGATE_SOURCE>
@ -871,8 +867,8 @@ public:
virtual RecordSource* compile(thread_db* tdbb, Optimizer* opt, bool innerSubStream);
private:
void planCheck(const CompilerScratch* csb) const;
static void planSet(CompilerScratch* csb, PlanNode* plan);
void planCheck(thread_db* tdbb, const CompilerScratch* csb) const;
static void planSet(thread_db* tdbb, CompilerScratch* csb, PlanNode* plan);
public:
NestConst<ValueExprNode> dsqlFirst;

View File

@ -43,22 +43,41 @@ using namespace Firebird;
/// jrd_rel
jrd_rel::jrd_rel(MemoryPool& p, MetaId id)
: rel_pool(&p), rel_id(id), rel_current_fmt(0),
rel_flags(REL_gc_lockneed), rel_current_format(nullptr),
rel_name(p), rel_owner_name(p), rel_security_name(p),
rel_formats(nullptr), rel_fields(nullptr),
rel_view_rse(nullptr), rel_view_contexts(p),
rel_file(nullptr), rel_gc_records(p),
rel_sweep_count(0), rel_scan_count(0),
rel_partners_lock(nullptr), rel_rescan_lock(nullptr),
rel_gc_lock(nullptr), rel_index_locks(p), rel_index_blocks(nullptr),
rel_pre_erase(nullptr), rel_post_erase(nullptr),
rel_pre_modify(nullptr), rel_post_modify(nullptr),
rel_pre_store(nullptr), rel_post_store(nullptr),
rel_ss_definer(false), rel_pages_inst(nullptr),
rel_pages_base(p), rel_pages_free(nullptr)
jrd_rel::jrd_rel(MemoryPool& p, RelationPermanent* r)
: rel_pool(&p),
rel_perm(r),
rel_current_fmt(0),
rel_flags(0),
rel_current_format(nullptr),
rel_fields(nullptr),
rel_view_rse(nullptr),
rel_view_contexts(p),
rel_scan_count(0),
rel_index_blocks(nullptr),
rel_ss_definer(false)
{ }
RelationPermanent::RelationPermanent(MemoryPool& p, MetaId id)
: PermanentStorage(p),
rel_existence_lock(nullptr),
rel_partners_lock(nullptr),
rel_rescan_lock(nullptr),
rel_gc_lock(this),
rel_gc_records(p),
rel_formats(nullptr),
rel_index_locks(getPool()),
rel_name(p),
rel_id(id),
rel_flags(0u),
rel_pages_inst(nullptr),
rel_pages_base(p),
rel_pages_free(nullptr),
rel_file(nullptr)
{ }
RelationPermanent::~RelationPermanent()
{
delete rel_file;
}
bool jrd_rel::isReplicating(thread_db* tdbb)
@ -71,12 +90,12 @@ bool jrd_rel::isReplicating(thread_db* tdbb)
attachment->checkReplSetLock(tdbb);
if (rel_repl_state.isUnknown())
rel_repl_state = MET_get_repl_state(tdbb, rel_name);
rel_repl_state = MET_get_repl_state(tdbb, getName());
return rel_repl_state.value;
}
RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages)
RelationPages* RelationPermanent::getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages)
{
if (tdbb->tdbb_flags & TDBB_use_db_page_space)
return &rel_pages_base;
@ -100,8 +119,10 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
else
inst_id = PAG_attachment_id(tdbb);
MutexLockGuard relPerm(rel_pages_mutex, FB_FUNCTION);
if (!rel_pages_inst)
rel_pages_inst = FB_NEW_POOL(*rel_pool) RelationPagesInstances(*rel_pool);
rel_pages_inst = FB_NEW_POOL(getPool()) RelationPagesInstances(getPool());
FB_SIZE_T pos;
if (!rel_pages_inst->find(inst_id, pos))
@ -111,7 +132,7 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
RelationPages* newPages = rel_pages_free;
if (!newPages) {
newPages = FB_NEW_POOL(*rel_pool) RelationPages(*rel_pool);
newPages = FB_NEW_POOL(getPool()) RelationPages(getPool());
}
else
{
@ -132,7 +153,7 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::getPages rel_id %u, inst %" UQUADFORMAT", ppp %" ULONGFORMAT", irp %" ULONGFORMAT", addr 0x%x\n",
rel_id,
getId(),
newPages->rel_instance_id,
newPages->rel_pages ? (*newPages->rel_pages)[0] : 0,
newPages->rel_index_root,
@ -167,7 +188,7 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::getPages rel_id %u, inst %" UQUADFORMAT", irp %" ULONGFORMAT", idx %u, idx_root %" ULONGFORMAT", addr 0x%x\n",
rel_id,
getId(),
newPages->rel_instance_id,
newPages->rel_index_root,
idx.idx_id,
@ -187,7 +208,7 @@ RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, TraNumber tran, bool a
return pages;
}
bool jrd_rel::delPages(thread_db* tdbb, TraNumber tran, RelationPages* aPages)
bool RelationPermanent::delPages(thread_db* tdbb, TraNumber tran, RelationPages* aPages)
{
RelationPages* pages = aPages ? aPages : getPages(tdbb, tran, false);
if (!pages || !pages->rel_instance_id)
@ -203,7 +224,7 @@ bool jrd_rel::delPages(thread_db* tdbb, TraNumber tran, RelationPages* aPages)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"jrd_rel::delPages rel_id %u, inst %" UQUADFORMAT", ppp %" ULONGFORMAT", irp %" ULONGFORMAT", addr 0x%x\n",
rel_id,
getId(),
pages->rel_instance_id,
pages->rel_pages ? (*pages->rel_pages)[0] : 0,
pages->rel_index_root,
@ -229,7 +250,7 @@ bool jrd_rel::delPages(thread_db* tdbb, TraNumber tran, RelationPages* aPages)
return true;
}
void jrd_rel::retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber)
void RelationPermanent::retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber)
{
fb_assert(rel_flags & REL_temp_tran);
fb_assert(oldNumber != 0);
@ -252,9 +273,9 @@ void jrd_rel::retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNum
rel_pages_inst->add(pages);
}
void jrd_rel::getRelLockKey(thread_db* tdbb, UCHAR* key)
void RelationPermanent::getRelLockKey(thread_db* tdbb, UCHAR* key)
{
const ULONG val = rel_id;
const ULONG val = getId();
memcpy(key, &val, sizeof(ULONG));
key += sizeof(ULONG);
@ -262,19 +283,19 @@ void jrd_rel::getRelLockKey(thread_db* tdbb, UCHAR* key)
memcpy(key, &inst_id, sizeof(inst_id));
}
USHORT jrd_rel::getRelLockKeyLength() const
USHORT constexpr RelationPermanent::getRelLockKeyLength()
{
return sizeof(ULONG) + sizeof(SINT64);
}
void jrd_rel::cleanUp()
void RelationPermanent::cleanUp()
{
delete rel_pages_inst;
rel_pages_inst = NULL;
}
void jrd_rel::fillPagesSnapshot(RelPagesSnapshot& snapshot, const bool attachmentOnly)
void RelationPermanent::fillPagesSnapshot(RelPagesSnapshot& snapshot, const bool attachmentOnly)
{
if (rel_pages_inst)
{
@ -311,7 +332,7 @@ void jrd_rel::fillPagesSnapshot(RelPagesSnapshot& snapshot, const bool attachmen
snapshot.add(&rel_pages_base);
}
void jrd_rel::RelPagesSnapshot::clear()
void RelationPermanent::RelPagesSnapshot::clear()
{
#ifdef DEV_BUILD
thread_db* tdbb = NULL;
@ -355,52 +376,50 @@ bool jrd_rel::hasTriggers() const
void jrd_rel::releaseTriggers(thread_db* tdbb, bool destroy)
{
MET_release_triggers(tdbb, &rel_pre_store, destroy);
MET_release_triggers(tdbb, &rel_post_store, destroy);
MET_release_triggers(tdbb, &rel_pre_erase, destroy);
MET_release_triggers(tdbb, &rel_post_erase, destroy);
MET_release_triggers(tdbb, &rel_pre_modify, destroy);
MET_release_triggers(tdbb, &rel_post_modify, destroy);
for (int n = 0; n < TRIGGER_MAX; ++n)
rel_triggers[n].release(tdbb, destroy);
}
void jrd_rel::replaceTriggers(thread_db* tdbb, TrigVectorPtr* triggers)
void Triggers::release(thread_db* tdbb, bool destroy)
{
TrigVectorPtr tmp_vector;
/***********************************************
*
* M E T _ r e l e a s e _ t r i g g e r s
*
***********************************************
*
* Functional description
* Release a possibly null vector of triggers.
* If triggers are still active let someone
* else do the work.
*
**************************************/
/* TrigVector* vector = vector_ptr->load(); !!!!!!!!!!!!!!!!!!!!!!!!!
tmp_vector.store(rel_pre_store.load());
rel_pre_store.store(triggers[TRIGGER_PRE_STORE].load());
MET_release_triggers(tdbb, &tmp_vector, true);
if (!vector)
return;
tmp_vector.store(rel_post_store.load());
rel_post_store.store(triggers[TRIGGER_POST_STORE].load());
MET_release_triggers(tdbb, &tmp_vector, true);
if (!destroy)
{
vector->decompile(tdbb);
return;
}
tmp_vector.store(rel_pre_erase.load());
rel_pre_erase.store(triggers[TRIGGER_PRE_ERASE].load());
MET_release_triggers(tdbb, &tmp_vector, true);
*vector_ptr = NULL;
tmp_vector.store(rel_post_erase.load());
rel_post_erase.store(triggers[TRIGGER_POST_ERASE].load());
MET_release_triggers(tdbb, &tmp_vector, true);
if (vector->hasActive())
return;
tmp_vector.store(rel_pre_modify.load());
rel_pre_modify.store(triggers[TRIGGER_PRE_MODIFY].load());
MET_release_triggers(tdbb, &tmp_vector, true);
tmp_vector.store(rel_post_modify.load());
rel_post_modify.store(triggers[TRIGGER_POST_MODIFY].load());
MET_release_triggers(tdbb, &tmp_vector, true);
vector->release(tdbb); */
}
Lock* jrd_rel::createLock(thread_db* tdbb, MemoryPool* pool, jrd_rel* relation, lck_t lckType, bool noAst)
Lock* RelationPermanent::createLock(thread_db* tdbb, lck_t lckType, bool noAst)
{
if (!pool)
pool = relation->rel_pool;
const USHORT relLockLen = getRelLockKeyLength();
const USHORT relLockLen = relation->getRelLockKeyLength();
Lock* lock = FB_NEW_RPT(*pool, relLockLen) Lock(tdbb, relLockLen, lckType, relation);
relation->getRelLockKey(tdbb, lock->getKeyPtr());
Lock* lock = FB_NEW_RPT(getPool(), relLockLen)
Lock(tdbb, relLockLen, lckType, lckType == LCK_relation ? (void*)this : (void*)&rel_gc_lock);
getRelLockKey(tdbb, lock->getKeyPtr());
lock->lck_type = lckType;
switch (lckType)
@ -409,7 +428,7 @@ Lock* jrd_rel::createLock(thread_db* tdbb, MemoryPool* pool, jrd_rel* relation,
break;
case LCK_rel_gc:
lock->lck_ast = noAst ? NULL : blocking_ast_gcLock;
lock->lck_ast = noAst ? nullptr : GCLock::ast;
break;
default:
@ -419,210 +438,231 @@ Lock* jrd_rel::createLock(thread_db* tdbb, MemoryPool* pool, jrd_rel* relation,
return lock;
}
bool jrd_rel::acquireGCLock(thread_db* tdbb, int wait)
void GCLock::blockingAst()
{
fb_assert(rel_flags & REL_gc_lockneed);
if (!(rel_flags & REL_gc_lockneed))
/****
SR - gc forbidden, awaiting moment to re-establish SW lock
SW - gc allowed, usual state
PW - gc allowed to the one connection only
****/
Database* dbb = lck->lck_dbb;
AsyncContextHolder tdbb(dbb, FB_FUNCTION, lck);
unsigned oldFlags = flags.load(std::memory_order_acquire);
do
{
fb_assert(rel_gc_lock->lck_id);
fb_assert(rel_gc_lock->lck_physical == (rel_flags & REL_gc_disabled ? LCK_SR : LCK_SW));
return true;
fb_assert(oldFlags & GC_locked);
if (!(oldFlags & GC_locked)) // work already done synchronously ?
return;
} while (!flags.compare_exchange_weak(oldFlags, oldFlags | GC_blocking,
std::memory_order_release, std::memory_order_acquire));
if (oldFlags & GC_counterMask)
return;
if (oldFlags & GC_disabled)
{
// someone acquired EX lock
fb_assert(lck->lck_id);
fb_assert(lck->lck_physical == LCK_SR);
LCK_release(tdbb, lck);
flags.fetch_and(~(GC_disabled | GC_blocking | GC_locked));
}
else
{
// someone acquired PW lock
fb_assert(lck->lck_id);
fb_assert(lck->lck_physical == LCK_SW);
flags.fetch_or(GC_disabled);
downgrade(tdbb);
}
}
bool GCLock::acquire(thread_db* tdbb, int wait)
{
unsigned oldFlags = flags.load(std::memory_order_acquire);
for(;;)
{
if (oldFlags & (GC_blocking | GC_disabled)) // lock should not be obtained
return false;
const unsigned newFlags = oldFlags + 1;
if (newFlags & GC_guardBit)
incrementError();
if (!flags.compare_exchange_weak(oldFlags, newFlags, std::memory_order_release, std::memory_order_acquire))
continue;
if (oldFlags & GC_locked) // lock was already taken when we checked flags
return true;
if (!(oldFlags & GC_counterMask)) // we must take lock
break;
// unstable state - someone else it getting a lock right now
// decrement counter, wait a bit and retry
--flags;
suspend();
oldFlags = flags.fetch_sub(1, std::memory_order_acquire); // reload after wait
}
if (!rel_gc_lock)
rel_gc_lock = createLock(tdbb, NULL, this, LCK_rel_gc, false);
// We incremented counter from 0 to 1 - take care about lck
if (!lck)
lck = relPerm->createLock(tdbb, LCK_rel_gc, false);
fb_assert(!rel_gc_lock->lck_id);
fb_assert(!(rel_flags & REL_gc_blocking));
fb_assert(!lck->lck_id);
ThreadStatusGuard temp_status(tdbb);
const USHORT level = (rel_flags & REL_gc_disabled) ? LCK_SR : LCK_SW;
bool ret = LCK_lock(tdbb, rel_gc_lock, level, wait);
if (!ret && (level == LCK_SW))
bool ret;
if (oldFlags & GC_disabled)
ret = LCK_lock(tdbb, lck, LCK_SR, wait);
else
{
rel_flags |= REL_gc_disabled;
ret = LCK_lock(tdbb, rel_gc_lock, LCK_SR, wait);
if (!ret)
rel_flags &= ~REL_gc_disabled;
}
if (ret)
rel_flags &= ~REL_gc_lockneed;
return ret;
}
void jrd_rel::downgradeGCLock(thread_db* tdbb)
{
if (!rel_sweep_count && (rel_flags & REL_gc_blocking))
{
fb_assert(!(rel_flags & REL_gc_lockneed));
fb_assert(rel_gc_lock->lck_id);
fb_assert(rel_gc_lock->lck_physical == LCK_SW);
rel_flags &= ~REL_gc_blocking;
rel_flags |= REL_gc_disabled;
LCK_downgrade(tdbb, rel_gc_lock);
if (rel_gc_lock->lck_physical != LCK_SR)
ret = LCK_lock(tdbb, lck, LCK_SW, wait);
if (ret)
{
rel_flags &= ~REL_gc_disabled;
if (rel_gc_lock->lck_physical < LCK_SR)
rel_flags |= REL_gc_lockneed;
}
}
}
int jrd_rel::blocking_ast_gcLock(void* ast_object)
{
/****
SR - gc forbidden, awaiting moment to re-establish SW lock
SW - gc allowed, usual state
PW - gc allowed to the one connection only
****/
jrd_rel* relation = static_cast<jrd_rel*>(ast_object);
try
{
Lock* lock = relation->rel_gc_lock;
Database* dbb = lock->lck_dbb;
AsyncContextHolder tdbb(dbb, FB_FUNCTION, lock);
fb_assert(!(relation->rel_flags & REL_gc_lockneed));
if (relation->rel_flags & REL_gc_lockneed) // work already done synchronously ?
return 0;
relation->rel_flags |= REL_gc_blocking;
if (relation->rel_sweep_count)
return 0;
if (relation->rel_flags & REL_gc_disabled)
{
// someone acquired EX lock
fb_assert(lock->lck_id);
fb_assert(lock->lck_physical == LCK_SR);
LCK_release(tdbb, lock);
relation->rel_flags &= ~(REL_gc_disabled | REL_gc_blocking);
relation->rel_flags |= REL_gc_lockneed;
flags.fetch_or(GC_locked);
return true;
}
else
{
// someone acquired PW lock
fb_assert(lock->lck_id);
fb_assert(lock->lck_physical == LCK_SW);
relation->rel_flags |= REL_gc_disabled;
relation->downgradeGCLock(tdbb);
flags.fetch_or(GC_disabled);
ret = LCK_lock(tdbb, lck, LCK_SR, wait);
}
}
catch (const Firebird::Exception&)
{} // no-op
return 0;
flags.fetch_sub(1, std::memory_order_release);
if (!ret)
flags.fetch_and(~GC_disabled, std::memory_order_release);
return false;
}
/// jrd_rel::GCExclusive
jrd_rel::GCExclusive::GCExclusive(thread_db* tdbb, jrd_rel* relation) :
m_tdbb(tdbb),
m_relation(relation),
m_lock(NULL)
void GCLock::downgrade(thread_db* tdbb)
{
unsigned oldFlags = flags.load(std::memory_order_acquire);
unsigned newFlags;
do
{
newFlags = oldFlags - 1;
if (newFlags & GC_guardBit)
incrementError();
if ((newFlags & GC_counterMask == 0) && (newFlags & GC_blocking))
{
fb_assert(oldFlags & GC_locked);
fb_assert(lck->lck_id);
fb_assert(lck->lck_physical == LCK_SW);
LCK_downgrade(tdbb, lck);
if (lck->lck_physical != LCK_SR)
{
newFlags &= ~GC_disabled;
if (lck->lck_physical < LCK_SR)
newFlags &= GC_locked;
}
else
newFlags |= GC_disabled;
newFlags &= ~GC_blocking;
}
} while (!flags.compare_exchange_weak(oldFlags, newFlags, std::memory_order_release, std::memory_order_acquire));
}
jrd_rel::GCExclusive::~GCExclusive()
bool GCLock::disable(thread_db* tdbb, int wait, Lock*& tempLock)
{
release();
delete m_lock;
}
ThreadStatusGuard temp_status(tdbb);
bool jrd_rel::GCExclusive::acquire(int wait)
{
// if validation is already running - go out
if (m_relation->rel_flags & REL_gc_disabled)
return false;
ThreadStatusGuard temp_status(m_tdbb);
m_relation->rel_flags |= REL_gc_disabled;
unsigned oldFlags = flags.load(std::memory_order_acquire);
do {
if (oldFlags & GC_disabled)
return false;
} while (flags.compare_exchange_weak(oldFlags, oldFlags | GC_disabled,
std::memory_order_release, std::memory_order_acquire));
int sleeps = -wait * 10;
while (m_relation->rel_sweep_count)
while (flags.load(std::memory_order_relaxed) & GC_counterMask)
{
EngineCheckout cout(m_tdbb, FB_FUNCTION);
EngineCheckout cout(tdbb, FB_FUNCTION);
Thread::sleep(100);
if (wait < 0 && --sleeps == 0)
break;
}
if (m_relation->rel_sweep_count)
if (flags.load(std::memory_order_relaxed) & GC_counterMask)
{
m_relation->rel_flags &= ~REL_gc_disabled;
flags.fetch_and(~GC_disabled);
return false;
}
if (!(m_relation->rel_flags & REL_gc_lockneed))
{
m_relation->rel_flags |= REL_gc_lockneed;
LCK_release(m_tdbb, m_relation->rel_gc_lock);
}
ensureReleased(tdbb);
// we need no AST here
if (!m_lock)
m_lock = jrd_rel::createLock(m_tdbb, NULL, m_relation, LCK_rel_gc, true);
if (!tempLock)
tempLock = relPerm->createLock(tdbb, LCK_rel_gc, true);
const bool ret = LCK_lock(m_tdbb, m_lock, LCK_PW, wait);
const bool ret = LCK_lock(tdbb, tempLock, LCK_PW, wait);
if (!ret)
m_relation->rel_flags &= ~REL_gc_disabled;
flags.fetch_and(~GC_disabled);
return ret;
}
void jrd_rel::GCExclusive::release()
void GCLock::ensureReleased(thread_db* tdbb)
{
if (!m_lock || !m_lock->lck_id)
unsigned oldFlags = flags.load(std::memory_order_acquire);
for (;;)
{
if (oldFlags & GC_locked)
{
if (!flags.compare_exchange_strong(oldFlags, oldFlags & ~GC_locked,
std::memory_order_release, std::memory_order_acquire))
{
continue;
}
// exactly one who cleared GC_locked bit releases a lock
LCK_release(tdbb, lck);
}
return;
}
}
void GCLock::enable(thread_db* tdbb, Lock* tempLock)
{
if (!lck || !lck->lck_id)
return;
fb_assert(m_relation->rel_flags & REL_gc_disabled);
fb_assert(flags.load() & GC_disabled);
if (!(m_relation->rel_flags & REL_gc_lockneed))
{
m_relation->rel_flags |= REL_gc_lockneed;
LCK_release(m_tdbb, m_relation->rel_gc_lock);
}
ensureReleased(tdbb);
LCK_convert(m_tdbb, m_lock, LCK_EX, LCK_WAIT);
m_relation->rel_flags &= ~REL_gc_disabled;
LCK_convert(tdbb, tempLock, LCK_EX, LCK_WAIT);
flags.fetch_and(~GC_disabled);
LCK_release(m_tdbb, m_lock);
LCK_release(tdbb, tempLock);
}
bool jrd_rel::checkObject(thread_db* tdbb, Arg::StatusVector& error)
{
bool rc = MetadataCache::checkRelation(tdbb, this);
if (!rc)
error << Arg::Gds(isc_relnotdef) << Arg::Str(rel_name);
error << Arg::Gds(isc_relnotdef) << Arg::Str(getName());
return rc;
}
void jrd_rel::afterUnlock(thread_db* tdbb, unsigned flags)
{
// release trigger requests
releaseTriggers(tdbb, false);
// close external file
EXT_fini(this, true);
}
/// RelationPages
void RelationPages::free(RelationPages*& nextFree)
@ -643,15 +683,7 @@ void RelationPages::free(RelationPages*& nextFree)
}
/// TrigVector
HazardPtr<Trigger> TrigVector::add(thread_db* tdbb, Trigger* trig)
{
FB_SIZE_T id = addCount.fetch_add(1);
return store(tdbb, id, trig);
}
HazardPtr<IndexLock> jrd_rel::getIndexLock(thread_db* tdbb, USHORT id)
IndexLock* RelationPermanent::getIndexLock(thread_db* tdbb, MetaId id)
{
/**************************************
*
@ -667,32 +699,31 @@ HazardPtr<IndexLock> jrd_rel::getIndexLock(thread_db* tdbb, USHORT id)
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
HazardPtr<IndexLock> indexLock;
if (rel_id < (USHORT) rel_MAX)
return indexLock;
if (getId() < (MetaId) rel_MAX)
return nullptr;
if (rel_index_locks.load(tdbb, id, indexLock))
return indexLock;
IndexLock* index = FB_NEW_POOL(*rel_pool) IndexLock(*rel_pool, tdbb, this, id);
return rel_index_locks.getObject(tdbb, id, CacheFlag::AUTOCREATE);
/*
IndexLock* index = FB_NEW_POOL(getPool()) IndexLock(getPool(), tdbb, this, id);
if (!rel_index_locks.replace(tdbb, id, indexLock, index))
delete index;
return indexLock;
*/
}
IndexLock::IndexLock(MemoryPool& p, thread_db* tdbb, jrd_rel* rel, USHORT id)
IndexLock::IndexLock(MemoryPool& p, thread_db* tdbb, RelationPermanent* rel, USHORT id)
: idl_relation(rel),
idl_id(id),
idl_lock(p, tdbb, LCK_idx_exist, (rel->rel_id << 16) | id, rel)
{ }
idl_lock(FB_NEW_RPT(p, 0) Lock(tdbb, sizeof(SLONG), LCK_idx_exist))
{
idl_lock->setKey((idl_relation->rel_id << 16) | id);
}
const char* IndexLock::c_name() const
{
return "* unk *";
}
static void jrd_rel::destroy(jrd_rel* rel)
void jrd_rel::destroy(jrd_rel* rel)
{
rel->rel_flags |= REL_deleted;
/*
@ -712,17 +743,18 @@ static void jrd_rel::destroy(jrd_rel* rel)
delete rel;
}
static jrd_rel* jrd_rel::create(thread_db* tdbb, MetaId id)
jrd_rel* jrd_rel::create(thread_db* tdbb, MemoryPool& pool, MetaId id, CacheObject::Flag flags)
{
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
MetadataCache* mdc = dbb->dbb_mdc;
MemoryPool& pool = mdc->getPool();
jrd_rel* relation = FB_NEW_POOL(pool) jrd_rel(pool, id);
relation->scan(tdbb, mdc);
RelationPermanent* rlp = mdc->lookupRelation(tdbb, id, flags & CacheFlag::NOSCAN);
jrd_rel* relation = FB_NEW_POOL(pool) jrd_rel(pool, rlp);
if (!(flags & CacheFlag::NOSCAN))
relation->scan(tdbb);
return relation;
}

View File

@ -22,6 +22,8 @@
#ifndef JRD_RELATION_H
#define JRD_RELATION_H
#include "../common/classes/RefCounted.h"
#include "../jrd/vec.h"
#include "../jrd/btr.h"
#include "../jrd/lck.h"
@ -30,6 +32,7 @@
#include "../jrd/Attachment.h"
#include "../jrd/HazardPtr.h"
#include "../jrd/ExtEngineManager.h"
#include "../jrd/met_proto.h"
namespace Jrd
{
@ -42,76 +45,69 @@ class jrd_fld;
class ExternalFile;
class IndexLock;
class IndexBlock;
class RelationPermanent;
class jrd_rel;
// trigger types
const int TRIGGER_PRE_STORE = 1;
const int TRIGGER_POST_STORE = 2;
const int TRIGGER_PRE_MODIFY = 3;
const int TRIGGER_POST_MODIFY = 4;
const int TRIGGER_PRE_ERASE = 5;
const int TRIGGER_POST_ERASE = 6;
const int TRIGGER_MAX = 7;
// trigger type prefixes
const int TRIGGER_PRE = 0;
const int TRIGGER_POST = 1;
// trigger type suffixes
const int TRIGGER_STORE = 1;
const int TRIGGER_MODIFY = 2;
const int TRIGGER_ERASE = 3;
// that's how trigger action types are encoded
/*
bit 0 = TRIGGER_PRE/TRIGGER_POST flag,
bits 1-2 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #1),
bits 3-4 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #2),
bits 5-6 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #3),
and finally the above calculated value is decremented
example #1:
TRIGGER_POST_ERASE =
= ((TRIGGER_ERASE << 1) | TRIGGER_POST) - 1 =
= ((3 << 1) | 1) - 1 =
= 0x00000110 (6)
example #2:
TRIGGER_PRE_STORE_MODIFY =
= ((TRIGGER_MODIFY << 3) | (TRIGGER_STORE << 1) | TRIGGER_PRE) - 1 =
= ((2 << 3) | (1 << 1) | 0) - 1 =
= 0x00010001 (17)
example #3:
TRIGGER_POST_MODIFY_ERASE_STORE =
= ((TRIGGER_STORE << 5) | (TRIGGER_ERASE << 3) | (TRIGGER_MODIFY << 1) | TRIGGER_POST) - 1 =
= ((1 << 5) | (3 << 3) | (2 << 1) | 1) - 1 =
= 0x00111100 (60)
*/
// that's how trigger types are decoded
#define TRIGGER_ACTION(value, shift) \
(((((value + 1) >> shift) & 3) << 1) | ((value + 1) & 1)) - 1
#define TRIGGER_ACTION_SLOT(value, slot) \
TRIGGER_ACTION(value, (slot * 2 - 1) )
const int TRIGGER_COMBINED_MAX = 128;
// Relation trigger definition
class Trigger : public CacheObject
class Trigger : public Firebird::RefCounted
{
/*
public:
Firebird::HalfStaticArray<UCHAR, 128> blr; // BLR code
Firebird::HalfStaticArray<UCHAR, 128> debugInfo; // Debug info
Statement* statement; // Compiled statement
bool releaseInProgress;
bool sysTrigger;
FB_UINT64 type; // Trigger type
USHORT flags; // Flags as they are in RDB$TRIGGERS table
jrd_rel* relation; // Trigger parent relation
MetaName name; // Trigger name
MetaName engine; // External engine name
Firebird::string entryPoint; // External trigger entrypoint
Firebird::string extBody; // External trigger body
ExtEngineManager::Trigger* extTrigger; // External trigger
Nullable<bool> ssDefiner;
MetaName owner; // Owner for SQL SECURITY
bool hasData() const
{
return name.hasData() || sysTrigger;
}
Key getKey() const
{
return name;
}
bool isActive() const;
void compile(thread_db*); // Ensure that trigger is compiled
int release(thread_db*); // Try to free trigger request
explicit Trigger(MemoryPool& p)
: blr(p),
debugInfo(p),
statement(nullptr),
releaseInProgress(false),
sysTrigger(false),
type(0),
flags(0),
relation(nullptr),
name(p),
engine(p),
entryPoint(p),
extBody(p),
extTrigger(NULL)
{}
virtual ~Trigger()
{
delete extTrigger;
}
void removeFromCache(thread_db* tdbb) override
{
delayedDelete(tdbb);
}
const char* c_name() const override
{
return name.c_str();
}
*/
public:
Firebird::HalfStaticArray<UCHAR, 128> blr; // BLR code
Firebird::HalfStaticArray<UCHAR, 128> debugInfo; // Debug info
@ -129,10 +125,12 @@ public:
Nullable<bool> ssDefiner;
MetaName owner; // Owner for SQL SECURITY
MemoryPool& getPool();
bool isActive() const;
void compile(thread_db*); // Ensure that trigger is compiled
void release(thread_db*); // Try to free trigger request
void free(thread_db*); // Try to free trigger request
explicit Trigger(MemoryPool& p)
: blr(p),
@ -151,19 +149,52 @@ public:
}
};
// Array of triggers (suppose separate arrays for triggers of different types)
class TrigVector
// Set of triggers (suppose separate arrays for triggers of different types)
class Triggers
{
public:
Triggers()
// : nullify everything needed
{ }
bool hasActive() const;
void decompile(thread_db* tdbb);
virtual ~TrigVector() { }
void addTrigger(thread_db* tdbb, Trigger* trigger);
virtual void addTrigger(thread_db* tdbb, Trigger* trigger) = 0;
Trigger** begin() const;
Trigger** end() const;
bool operator!() const;
operator bool() const;
//bool hasData() const;
void release(thread_db* tdbb, bool destroy);
static void destroy(Triggers* trigs);
private:
// implementation ...
};
typedef std::atomic<TrigVector*> TrigVectorPtr;
typedef Triggers* TrigVectorPtr;
class DbTriggers final : public Triggers, public CacheObject
{
public:
DbTriggers()
: Triggers(), CacheObject()
{ }
static DbTriggers* create(thread_db* tdbb, MemoryPool& pool, MetaId type, CacheObject::Flag);
/*
return FB_NEW_POOL(pool) DbTriggers();
*/
const char* c_name() const override
{
return "Trigger's set";
}
};
// view context block to cache view aliases
@ -321,7 +352,7 @@ private:
Firebird::SortedArray<DPItem, Firebird::InlineStorage<DPItem, MAX_DPMAP_ITEMS>, ULONG, DPItem> dpMap;
ULONG dpMapMark;
friend class jrd_rel;
friend class RelationPermanent;
};
@ -356,73 +387,59 @@ struct frgn
// Index lock block
class IndexLock : public CacheObject
class IndexLock final : public CacheObject
{
public:
typedef USHORT Key;
IndexLock(MemoryPool& p, thread_db* tdbb, jrd_rel* rel, USHORT id);
IndexLock(MemoryPool& p, thread_db* tdbb, RelationPermanent* rel, USHORT id);
~IndexLock()
{
fb_assert(idl_lock.getUseCount() == 0);
}
{ }
jrd_rel* idl_relation; // Parent relation
private:
RelationPermanent* idl_relation; // Parent relation
USHORT idl_id; // Index id
ExistenceLock idl_lock; // Lock block
Lock* idl_lock; // Lock block
public:
bool hasData() { return true; }
const char* c_name() const override;
const char* c_name() const;
static void destroy(IndexLock *idl);
static IndexLock* create(thread_db* tdbb, MemoryPool& p, MetaId id, CacheObject::Flag flags);
static Lock* getLock(MemoryPool& p, thread_db* tdbb);
void lockShared(thread_db* tdbb);
void lockExclusive(thread_db* tdbb);
void unlock(thread_db* tdbb);
void unlockAll(thread_db* tdbb);
};
// Relation block; one is created for each relation referenced
// in the database, though it is not really filled out until
// the relation is scanned
typedef CacheElement<jrd_rel, RelationPermanent> CachedRelation;
class jrd_rel final : public CacheObject
{
typedef Firebird::HalfStaticArray<Record*, 4> GCRecordList;
typedef Firebird::ObjectsArray<IndexLock> IndexLocks;
public:
jrd_rel(MemoryPool& p, RelationPermanent* r);
MemoryPool* rel_pool;
USHORT rel_id;
RelationPermanent* rel_perm;
USHORT rel_current_fmt; // Current format number
ULONG rel_flags;
Format* rel_current_format; // Current record format
MetaName rel_name; // ascii relation name
MetaName rel_owner_name; // ascii owner
MetaName rel_security_name; // security class name for relation
vec<Format*>* rel_formats; // Known record formats
vec<jrd_fld*>* rel_fields; // vector of field blocks
RseNode* rel_view_rse; // view record select expression
ViewContexts rel_view_contexts; // sorted array of view contexts
ExternalFile* rel_file; // external file name
GCRecordList rel_gc_records; // records for garbage collection
USHORT rel_sweep_count; // sweep and/or garbage collector threads active
SSHORT rel_scan_count; // concurrent sequential scan count
Firebird::AutoPtr<ExistenceLock> rel_existence_lock; // existence lock, if any
Lock* rel_partners_lock; // partners lock
Lock* rel_rescan_lock; // lock forcing relation to be scanned
Lock* rel_gc_lock; // garbage collection lock
IndexLocks rel_index_locks; // index existence locks
//Firebird::Mutex rel_mtx_il; // controls addition & removal of elements
IndexBlock* rel_index_blocks; // index blocks for caching index info
TrigVectorPtr rel_pre_erase; // Pre-operation erase trigger
TrigVectorPtr rel_post_erase; // Post-operation erase trigger
TrigVectorPtr rel_pre_modify; // Pre-operation modify trigger
TrigVectorPtr rel_post_modify; // Post-operation modify trigger
TrigVectorPtr rel_pre_store; // Pre-operation store trigger
TrigVectorPtr 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
Nullable<bool> rel_ss_definer;
@ -431,146 +448,33 @@ public:
Firebird::Mutex rel_drop_mutex, rel_trig_load_mutex;
bool isSystem() const;
bool isTemporary() const;
bool isVirtual() const;
bool isView() const;
bool hasData() const
{
return rel_name.hasData();
}
Triggers rel_triggers[TRIGGER_MAX];
bool isReplicating(thread_db* tdbb);
// global temporary relations attributes
bool hasData() const;
const char* c_name() const override;
MetaId getId() const;
RelationPages* getPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, bool allocPages = true);
bool isTemporary() const;
bool isView() const;
bool isVirtual() const;
bool isSystem() const;
RelationPages* getBasePages()
{
return &rel_pages_base;
}
const char* c_name() const override
{
return rel_name.c_str();
}
USHORT getId()
{
return rel_id;
}
void scan(thread_db* tdbb);
/*
// Scan the relation if it hasn't already been scanned for meta data
- if (!(node->relation->rel_flags & REL_scanned) ||
- (node->relation->rel_flags & REL_being_scanned))
- {
- MET_scan_relation(tdbb, this);
- }
*/
bool delPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL);
void retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber);
void getRelLockKey(thread_db* tdbb, UCHAR* key);
USHORT 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);
void scan(thread_db* tdbb); // Scan the newly loaded relation for meta data
MetaName getName() const;
MemoryPool& getPool() const;
MetaName getSecurityName() const;
ExternalFile* getExtFile();
bool checkObject(thread_db* tdbb, Firebird::Arg::StatusVector&) override;
void afterUnlock(thread_db* tdbb, unsigned flags) override;
static void destroy(jrd_rel *rel);
static jrd_rel* create(thread_db* tdbb, MetaId id, CacheObject::Flag flags);
private:
typedef Firebird::SortedArray<
RelationPages*,
Firebird::EmptyStorage<RelationPages*>,
RelationPages::InstanceId,
RelationPages>
RelationPagesInstances;
RelationPagesInstances* rel_pages_inst;
RelationPages rel_pages_base;
RelationPages* rel_pages_free;
RelationPages* getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages);
static jrd_rel* create(thread_db* tdbb, MemoryPool& p, MetaId id, CacheObject::Flag flags);
public:
jrd_rel(MemoryPool& p, MetaId id);
// bool hasTriggers() const; unused ???????????????????
void releaseTriggers(thread_db* tdbb, bool destroy);
void replaceTriggers(thread_db* tdbb, TrigVectorPtr* triggers);
static Lock* createLock(thread_db* tdbb, MemoryPool* pool, jrd_rel* relation, lck_t, bool);
static int blocking_ast_gcLock(void*);
void downgradeGCLock(thread_db* tdbb);
bool acquireGCLock(thread_db* tdbb, int wait);
HazardPtr<IndexLock> getIndexLock(thread_db* tdbb, USHORT id);
// This guard is used by regular code to prevent online validation while
// dead- or back- versions is removed from disk.
class GCShared
{
public:
GCShared(thread_db* tdbb, jrd_rel* relation);
~GCShared();
bool gcEnabled() const
{
return m_gcEnabled;
}
private:
thread_db* m_tdbb;
jrd_rel* m_relation;
bool m_gcEnabled;
};
// This guard is used by online validation to prevent any modifications of
// table data while it is checked.
class GCExclusive
{
public:
GCExclusive(thread_db* tdbb, jrd_rel* relation);
~GCExclusive();
bool acquire(int wait);
void release();
private:
thread_db* m_tdbb;
jrd_rel* m_relation;
Lock* m_lock;
};
};
// rel_flags
@ -591,34 +495,303 @@ const ULONG REL_temp_tran = 0x1000; // relation is a GTT delete rows
const ULONG REL_temp_conn = 0x2000; // relation is a GTT preserve rows
const ULONG REL_virtual = 0x4000; // relation is virtual
const ULONG REL_jrd_view = 0x8000; // relation is VIEW
const ULONG REL_gc_blocking = 0x10000; // request to downgrade\release gc lock
const ULONG REL_gc_disabled = 0x20000; // gc is disabled temporarily
const ULONG REL_gc_lockneed = 0x40000; // gc lock should be acquired
const ULONG REL_perm_flags = REL_check_existence | REL_blocking | REL_check_partners |
REL_temp_tran | REL_temp_conn | REL_virtual | REL_jrd_view |
REL_system | REL_virtual | REL_jrd_view;
const ULONG REL_version_flags = (~REL_perm_flags) & 0x7FFFF;
/// class jrd_rel
inline bool jrd_rel::isSystem() const
class GCLock
{
return rel_flags & REL_system;
public:
GCLock(RelationPermanent* rl)
: lck(nullptr),
relPerm(rl),
flags(0u)
{ }
// This guard is used by regular code to prevent online validation while
// dead- or back- versions is removed from disk.
class Shared
{
public:
Shared(thread_db* tdbb, RelationPermanent* rl);
~Shared();
bool gcEnabled() const
{
return m_gcEnabled;
}
private:
thread_db* m_tdbb;
RelationPermanent* m_rl;
bool m_gcEnabled;
};
// This guard is used by online validation to prevent any modifications of
// table data while it is checked.
class Exclusive
{
public:
Exclusive(thread_db* tdbb, RelationPermanent* rl)
: m_tdbb(tdbb), m_rl(rl), m_lock(nullptr)
{ }
~Exclusive()
{
release();
delete m_lock;
}
bool acquire(int wait);
void release();
private:
thread_db* m_tdbb;
RelationPermanent* m_rl;
Lock* m_lock;
};
public:
bool acquire(thread_db* tdbb, int wait);
void downgrade(thread_db* tdbb);
void enable(thread_db* tdbb, Lock* tempLock);
bool disable(thread_db* tdbb, int wait, Lock*& tempLock);
static int ast(void* self)
{
try
{
reinterpret_cast<GCLock*>(self)->blockingAst();
}
catch(const Firebird::Exception&) { }
return 0;
}
private:
void blockingAst();
void ensureReleased(thread_db* tdbb);
void incrementError [[noreturn]] ();
private:
Firebird::AutoPtr<Lock> lck;
RelationPermanent* relPerm;
std::atomic<unsigned> flags;
static const unsigned GC_counterMask = 0x0FFFFFFF;
static const unsigned GC_guardBit = 0x10000000;
static const unsigned GC_disabled = 0x20000000;
static const unsigned GC_locked = 0x40000000;
static const unsigned GC_blocking = 0x80000000;
};
// Non-versioned part of relation in cache
class RelationPermanent : public Firebird::PermanentStorage
{
// typedef Firebird::ObjectsArray<IndexLock> IndexLocks;
typedef CacheVector<IndexLock> IndexLocks;
typedef Firebird::HalfStaticArray<Record*, 4> GCRecordList;
public:
RelationPermanent(MemoryPool& p, MetaId id);
~RelationPermanent();
void makeLocks(thread_db* tdbb, CachedRelation* relation);
static constexpr USHORT getRelLockKeyLength();
Lock* createLock(thread_db* tdbb, lck_t, bool);
void extFile(thread_db* tdbb, const TEXT* file_name); // impl in ext.cpp
IndexLock* getIndexLock(thread_db* tdbb, USHORT id);
Lock* rel_existence_lock; // existence lock
Lock* rel_partners_lock; // partners lock
Lock* rel_rescan_lock; // lock forcing relation to be scanned
GCLock rel_gc_lock; // garbage collection lock
GCRecordList rel_gc_records; // records for garbage collection
class RelPagesSnapshot : public Firebird::Array<RelationPages*>
{
public:
typedef Firebird::Array<RelationPages*> inherited;
RelPagesSnapshot(thread_db* tdbb, RelationPermanent* relation)
{
spt_tdbb = tdbb;
spt_relation = relation;
}
~RelPagesSnapshot() { clear(); }
void clear();
private:
thread_db* spt_tdbb;
RelationPermanent* spt_relation;
friend class RelationPermanent;
};
RelationPages* getPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, bool allocPages = true);
bool delPages(thread_db* tdbb, TraNumber tran = MAX_TRA_NUMBER, RelationPages* aPages = NULL);
void retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNumber);
void cleanUp();
void fillPagesSnapshot(RelPagesSnapshot&, const bool AttachmentOnly = false);
RelationPages* getBasePages()
{
return &rel_pages_base;
}
bool hasData() const
{
return rel_name.hasData();
}
const char* c_name() const
{
return rel_name.c_str();
}
MetaName getName() const
{
return rel_name;
}
MetaId getId() const
{
return rel_id;
}
ExternalFile* getExtFile()
{
return rel_file;
}
void getRelLockKey(thread_db* tdbb, UCHAR* key);
bool isSystem() const;
bool isTemporary() const;
bool isVirtual() const;
bool isView() const;
vec<Format*>* rel_formats; // Known record formats
IndexLocks rel_index_locks; // index existence locks
MetaName rel_name; // ascii relation name
MetaId rel_id;
MetaName rel_owner_name; // ascii owner
MetaName rel_security_name; // security class name for relation
ULONG rel_flags; // lock-related flags
private:
Firebird::Mutex rel_pages_mutex;
typedef Firebird::SortedArray<
RelationPages*,
Firebird::EmptyStorage<RelationPages*>,
RelationPages::InstanceId,
RelationPages>
RelationPagesInstances;
RelationPagesInstances* rel_pages_inst;
RelationPages rel_pages_base;
RelationPages* rel_pages_free;
RelationPages* getPagesInternal(thread_db* tdbb, TraNumber tran, bool allocPages);
ExternalFile* rel_file;
};
inline bool jrd_rel::hasData() const
{
return rel_perm->rel_name.hasData();
}
inline const char* jrd_rel::c_name() const
{
return rel_perm->rel_name.c_str();
}
inline MetaName jrd_rel::getName() const
{
return rel_perm->rel_name;
}
inline MemoryPool& jrd_rel::getPool() const
{
return rel_perm->getPool();
}
inline ExternalFile* jrd_rel::getExtFile()
{
return rel_perm->getExtFile();
}
inline MetaName jrd_rel::getSecurityName() const
{
return rel_perm->rel_security_name;
}
inline MetaId jrd_rel::getId() const
{
return rel_perm->rel_id;
}
RelationPages* jrd_rel::getPages(thread_db* tdbb, TraNumber tran, bool allocPages)
{
return rel_perm->getPages(tdbb, tran, allocPages);
}
inline bool jrd_rel::isTemporary() const
{
return (rel_flags & (REL_temp_tran | REL_temp_conn));
}
inline bool jrd_rel::isVirtual() const
{
return (rel_flags & REL_virtual);
return rel_perm->isTemporary();
}
inline bool jrd_rel::isView() const
{
return rel_perm->isView();
}
inline bool jrd_rel::isVirtual() const
{
return rel_perm->isVirtual();
}
inline bool jrd_rel::isSystem() const
{
return rel_perm->isSystem();
}
inline bool RelationPermanent::isSystem() const
{
return rel_flags & REL_system;
}
inline bool RelationPermanent::isTemporary() const
{
return (rel_flags & (REL_temp_tran | REL_temp_conn));
}
inline bool RelationPermanent::isVirtual() const
{
return (rel_flags & REL_virtual);
}
inline bool RelationPermanent::isView() const
{
return (rel_flags & REL_jrd_view);
}
inline RelationPages* jrd_rel::getPages(thread_db* tdbb, TraNumber tran, bool allocPages)
inline RelationPages* RelationPermanent::getPages(thread_db* tdbb, TraNumber tran, bool allocPages)
{
if (!isTemporary())
return &rel_pages_base;
@ -626,36 +799,28 @@ inline RelationPages* jrd_rel::getPages(thread_db* tdbb, TraNumber tran, bool al
return getPagesInternal(tdbb, tran, allocPages);
}
/// class jrd_rel::GCShared
inline jrd_rel::GCShared::GCShared(thread_db* tdbb, jrd_rel* relation)
/// class GCLock::Shared
inline GCLock::Shared::Shared(thread_db* tdbb, RelationPermanent* rl)
: m_tdbb(tdbb),
m_relation(relation),
m_gcEnabled(false)
{
if (m_relation->rel_flags & (REL_gc_blocking | REL_gc_disabled))
return;
m_rl(rl),
m_gcEnabled(m_rl->rel_gc_lock.acquire(m_tdbb, LCK_NO_WAIT))
{ }
if (m_relation->rel_flags & REL_gc_lockneed)
m_relation->acquireGCLock(tdbb, LCK_NO_WAIT);
if (!(m_relation->rel_flags & (REL_gc_blocking | REL_gc_disabled | REL_gc_lockneed)))
{
++m_relation->rel_sweep_count;
m_gcEnabled = true;
}
if ((m_relation->rel_flags & REL_gc_blocking) && !m_relation->rel_sweep_count)
m_relation->downgradeGCLock(m_tdbb);
}
inline jrd_rel::GCShared::~GCShared()
inline GCLock::Shared::~Shared()
{
if (m_gcEnabled)
--m_relation->rel_sweep_count;
m_rl->rel_gc_lock.downgrade(m_tdbb);
}
if ((m_relation->rel_flags & REL_gc_blocking) && !m_relation->rel_sweep_count)
m_relation->downgradeGCLock(m_tdbb);
/// class GCLock::Exclusive
inline bool GCLock::Exclusive::acquire(int wait)
{
return m_rl->rel_gc_lock.disable(m_tdbb, wait, m_lock);
}
@ -690,6 +855,6 @@ public:
}
};
}
};
#endif // JRD_RELATION_H

View File

@ -1,43 +0,0 @@
/*
* PROGRAM: JRD Access Method
* MODULE: Resource.cpp
* DESCRIPTION: Resource used by request / transaction
*
* 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): ______________________________________.
*
* 2001.07.28: Added rse_skip to class RecordSelExpr to support LIMIT.
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
* Adriano dos Santos Fernandes
*/
#include "firebird.h"
#include "../jrd/Resource.h"
#include "../jrd/Relation.h"
using namespace Jrd;
USHORT Resource::relId() const
{
return rsc_rel ? rsc_rel->rel_id : 0;
}

View File

@ -32,11 +32,288 @@
#ifndef JRD_RESOURCE_H
#define JRD_RESOURCE_H
#include "../jrd/MetaName.h"
#include "../common/classes/Bits.h"
#include "fb_blk.h"
#include "../jrd/HazardPtr.h"
namespace Jrd {
class RelationPermanent;
class RoutinePermanent;
class CharSetContainer;
class jrd_rel;
class jrd_prc;
class Function;
class Trigger;
class CharSetVers;
class Resources;
// Set of objects cached per particular MDC version
union VersionedPartPtr
{
jrd_rel* relation;
jrd_prc* procedure;
Function* function;
};
class VersionedObjects : public pool_alloc_rpt<VersionedPartPtr>,
public Firebird::RefCounted
{
public:
VersionedObjects(FB_SIZE_T cnt, MdcVersion ver) :
version(ver),
capacity(cnt)
{ }
template <class C>
void put(FB_SIZE_T n, C* obj)
{
fb_assert(n < capacity);
fb_assert(!object<C>(n));
object<C>(n) = obj;
}
template <class C>
C* get(FB_SIZE_T n) const
{
fb_assert(n < capacity);
return object<C>(n);
}
FB_SIZE_T getCapacity()
{
return capacity;
}
const MdcVersion version; // version when created
private:
FB_SIZE_T capacity;
VersionedPartPtr data[1];
template <class C> C*& object(FB_SIZE_T n);
template <class C> C* object(FB_SIZE_T n) const;
};
// specialization
template <> Function*& VersionedObjects::object<Function>(FB_SIZE_T n) { return data[n].function; }
template <> jrd_prc*& VersionedObjects::object<jrd_prc>(FB_SIZE_T n) { return data[n].procedure; }
template <> jrd_rel*& VersionedObjects::object<jrd_rel>(FB_SIZE_T n) { return data[n].relation; }
template <> jrd_rel* VersionedObjects::object<jrd_rel>(FB_SIZE_T n) const { return data[n].relation; }
//template <> *& object<*>(FB_SIZE_T n) { check(n); return data[n].; }
template <class OBJ, class PERM>
class CachedResource
{
public:
CachedResource(CacheElement<OBJ, PERM>* elem, FB_SIZE_T version)
: cacheElement(elem), versionOffset(version)
{ }
CachedResource()
: cacheElement(nullptr)
{ }
OBJ* operator()(const VersionedObjects* runTime) const
{
return runTime->get<OBJ>(versionOffset);
}
OBJ* operator()(thread_db* tdbb) const
{
return cacheElement->getObject(tdbb);
}
CacheElement<OBJ, PERM>* operator()() const
{
return cacheElement;
}
FB_SIZE_T getOffset() const
{
return versionOffset;
}
void clear()
{
cacheElement = nullptr;
}
bool isSet() const
{
return cacheElement != nullptr;
}
operator bool() const
{
return isSet();
}
bool operator!() const
{
return !isSet();
}
private:
CacheElement<OBJ, PERM>* cacheElement;
FB_SIZE_T versionOffset;
};
class Resources
{
public:
template <class OBJ, class PERM>
class RscArray : public Firebird::Array<CachedResource<OBJ, PERM>>
{
public:
RscArray(MemoryPool& p, FB_SIZE_T& pos)
: Firebird::Array<CachedResource<OBJ, PERM>>(p),
versionCurrentPosition(pos)
{ }
CachedResource<OBJ, PERM>& registerResource(CacheElement<OBJ, PERM>* res)
{
FB_SIZE_T pos;
if (!this->find([res](const CachedResource<OBJ, PERM>& elem) {
const void* p1 = elem();
const void* p2 = res;
return p1 < p2 ? -1 : p1 == p2 ? 0 : 1;
}, pos))
{
CachedResource<OBJ, PERM> newPtr(res, versionCurrentPosition++);
pos = this->add(newPtr);
}
return this->getElement(pos);
}
void transfer(thread_db* tdbb, VersionedObjects* to)
{
for (auto& resource : *this)
to->put(resource.getOffset(), resource()->getObject(tdbb));
}
private:
FB_SIZE_T& versionCurrentPosition;
};
void transfer(thread_db* tdbb, VersionedObjects* to); // Impl-ted in Statement.cpp
private:
FB_SIZE_T versionCurrentPosition;
public:
template <class OBJ, class PERM> const RscArray<OBJ, PERM>& objects() const;
Resources(MemoryPool& p)
: versionCurrentPosition(0),
charSets(p, versionCurrentPosition),
relations(p, versionCurrentPosition),
procedures(p, versionCurrentPosition),
functions(p, versionCurrentPosition),
triggers(p, versionCurrentPosition)
{ }
RscArray<CharSetVers, CharSetContainer> charSets;
RscArray<jrd_rel, RelationPermanent> relations;
RscArray<jrd_prc, RoutinePermanent> procedures;
RscArray<Function, RoutinePermanent> functions;
RscArray<Trigger, NullClass> triggers;
};
// specialization
template <> const Resources::RscArray<jrd_rel, RelationPermanent>& Resources::objects() const { return relations; }
template <> const Resources::RscArray<jrd_prc, RoutinePermanent>& Resources::objects() const { return procedures; }
template <> const Resources::RscArray<Function, RoutinePermanent>& Resources::objects() const { return functions; }
template <> const Resources::RscArray<CharSetVers, CharSetContainer>& Resources::objects() const { return charSets; }
template <> const Resources::RscArray<Trigger, NullClass>& Resources::objects() const { return triggers; }
namespace Rsc
{
typedef CachedResource<jrd_rel, RelationPermanent> Rel;
typedef CachedResource<jrd_prc, RoutinePermanent> Proc;
typedef CachedResource<Function, RoutinePermanent> Fun;
typedef CachedResource<CharSetVers, CharSetContainer> CSet;
typedef CachedResource<Trigger, NullClass> Trig;
}; //namespace Rsc
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
// -------------------------------------------------------------------------- //
/*
class jrd_rel;
class Routine;
class Collation;
@ -126,6 +403,8 @@ struct Resource
USHORT relId() const;
};
*/
} // namespace Jrd
#endif // JRD_RESOURCE_H

View File

@ -35,6 +35,20 @@ using namespace Firebird;
namespace Jrd {
RoutinePermanent::RoutinePermanent(MemoryPool& p, MetaId metaId, Lock* existence)
: PermanentStorage(p),
id(metaId),
name(p),
securityName(p),
subRoutine(false),
flags(0),
alterCount(0),
existenceLock(existence)
{
existenceLock->setKey(metaId);
existenceLock->lck_object = this;
}
// Create a MsgMetadata from a parameters array.
MsgMetadata* Routine::createMetadata(const Array<NestConst<Parameter> >& parameters, bool isExtern)
@ -258,51 +272,6 @@ void Routine::parseMessages(thread_db* tdbb, CompilerScratch* csb, BlrReader blr
}
}
// Decrement the routine's use count.
void Routine::afterDecrement(thread_db* tdbb)
{
// intUseCount != 0 if and only if we are cleaning cache
if (intUseCount > 0)
intUseCount--;
}
void Routine::afterUnlock(thread_db* tdbb, unsigned fl)
{
flags |= Routine::FLAG_OBSOLETE;
// Call recursively if and only if the use count is zero AND the routine
// in the cache is different than this routine.
// The routine will be different than in the cache only if it is a
// floating copy, i.e. an old copy or a deleted routine.
if (!(fl & ExistenceLock::inCache))
{
if (getStatement())
releaseStatement(tdbb);
flags &= ~Routine::FLAG_BEING_ALTERED;
//remove(tdbb);
}
}
int Routine::getUseCount() const
{
return existenceLock.hasData() ? existenceLock->getUseCount() : 1;
}
void Routine::sharedCheckLock(thread_db* tdbb)
{
if (existenceLock->inc(tdbb) != Resource::State::Locked)
existenceLock->enter245(tdbb);
}
void Routine::sharedCheckUnlock(thread_db* tdbb)
{
existenceLock->dec(tdbb);
existenceLock->releaseLock(tdbb, ExistenceLock::ReleaseMethod::DropObject);
}
void Routine::releaseStatement(thread_db* tdbb)
{
if (getStatement())
@ -362,51 +331,8 @@ bool jrd_prc::checkCache(thread_db* tdbb) const
void Routine::releaseLocks(thread_db* tdbb)
{
if (existenceLock)
{
existenceLock->releaseLock(tdbb, ExistenceLock::ReleaseMethod::CloseCache);
flags |= Routine::FLAG_CHECK_EXISTENCE;
}
if (permanent->existenceLock)
LCK_release(tdbb, permanent->existenceLock);
}
void Routine::adjust_dependencies()
{
if (intUseCount == -1)
{
// Already processed
return;
}
intUseCount = -1; // Mark as undeletable
if (getStatement())
{
// Loop over procedures from resource list of request
for (auto resource : getStatement()->resources.getObjects(Resource::rsc_procedure))
{
auto routine = resource->rsc_routine;
if (routine->intUseCount == routine->getUseCount())
{
// Mark it and all dependent procedures as undeletable
routine->adjust_dependencies();
}
}
for (auto resource : getStatement()->resources.getObjects(Resource::rsc_function))
{
auto routine = resource->rsc_routine;
if (routine->intUseCount == routine->getUseCount())
{
// Mark it and all dependent functions as undeletable
routine->adjust_dependencies();
}
}
}
}
} // namespace Jrd

View File

@ -44,8 +44,6 @@ namespace Jrd
class Format;
class Parameter;
class UserId;
class ExistenceLock;
class StartupBarrier
{
public:
@ -91,82 +89,21 @@ namespace Jrd
bool flg;
};
class Routine : public Firebird::PermanentStorage, public CacheObject
class RoutinePermanent : public Firebird::PermanentStorage
{
protected:
explicit Routine(MemoryPool& p)
public:
explicit RoutinePermanent(MemoryPool& p, MetaId metaId, Lock* existence);
explicit RoutinePermanent(MemoryPool& p)
: PermanentStorage(p),
id(~0),
name(p),
securityName(p),
statement(NULL),
subRoutine(true),
implemented(true),
defined(true),
defaultCount(0),
inputFormat(NULL),
outputFormat(NULL),
inputFields(p),
outputFields(p),
flags(0),
intUseCount(0),
alterCount(0),
existenceLock(NULL),
invoker(NULL)
{
}
explicit Routine(MemoryPool& p, MetaId metaId)
: PermanentStorage(p),
id(metaId),
name(p),
securityName(p),
statement(NULL),
subRoutine(false),
implemented(true),
defined(true),
defaultCount(0),
inputFormat(NULL),
outputFormat(NULL),
inputFields(p),
outputFields(p),
flags(0),
intUseCount(0),
alterCount(0),
existenceLock(NULL),
invoker(NULL)
{
}
public:
virtual ~Routine()
{
}
public:
static const USHORT FLAG_SCANNED = 1; // Field expressions scanned
static const USHORT FLAG_OBSOLETE = 2; // Procedure known gonzo
static const USHORT FLAG_BEING_SCANNED = 4; // New procedure needs dependencies during scan
static const USHORT FLAG_BEING_ALTERED = 8; // Procedure is getting altered
// This flag is used to make sure that MET_remove_routine
// 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
static const USHORT FLAG_CHECK_EXISTENCE = 16; // Existence lock released
static const USHORT FLAG_RELOAD = 32; // Recompile before execution
static const USHORT FLAG_CLEARED = 64; // Routine cleared but not removed from cache
static const USHORT MAX_ALTER_COUNT = 64; // Number of times an in-cache routine can be altered
static Firebird::MsgMetadata* createMetadata(
const Firebird::Array<NestConst<Parameter> >& parameters, bool isExtern);
static Format* createFormat(MemoryPool& pool, Firebird::IMessageMetadata* params, bool addEof);
public:
static void destroy(Routine* routine)
{
delete routine;
}
existenceLock(NULL)
{ }
USHORT getId() const
{
@ -178,17 +115,74 @@ namespace Jrd
const QualifiedName& getName() const { return name; }
void setName(const QualifiedName& value) { name = value; }
const char* c_name() const override { return name.c_str(); }
const char* c_name() const { return name.c_str(); }
const MetaName& getSecurityName() const { return securityName; }
void setSecurityName(const MetaName& value) { securityName = value; }
/*const*/ Statement* getStatement() const { return statement; }
void setStatement(Statement* value);
bool hasData() const { return name.hasData(); }
bool isSubRoutine() const { return subRoutine; }
void setSubRoutine(bool value) { subRoutine = value; }
int getObjectType() const;
private:
USHORT id; // routine ID
QualifiedName name; // routine name
MetaName securityName; // security class name
bool subRoutine; // Is this a subroutine?
USHORT flags;
USHORT alterCount; // No. of times the routine was altered
public:
Lock* existenceLock; // existence lock, if any
MetaName owner;
};
class Routine : public CacheObject
{
protected:
explicit Routine(RoutinePermanent* perm)
: permanent(perm),
statement(NULL),
implemented(true),
defined(true),
defaultCount(0),
inputFormat(NULL),
outputFormat(NULL),
inputFields(permanent->getPool()),
outputFields(permanent->getPool()),
flags(0),
invoker(NULL)
{
}
public:
virtual ~Routine()
{
}
public:
static const USHORT MAX_ALTER_COUNT = 64; // Number of times an in-cache routine can be altered ?????????
static Firebird::MsgMetadata* createMetadata(
const Firebird::Array<NestConst<Parameter> >& parameters, bool isExtern);
static Format* createFormat(MemoryPool& pool, Firebird::IMessageMetadata* params, bool addEof);
public:
static void destroy(Routine* routine)
{
delete routine;
}
const QualifiedName& getName() const { return permanent->getName(); }
USHORT getId() const { return permanent->getId(); }
const char* c_name() const override { return permanent->c_name(); }
/*const*/ Statement* getStatement() const { return statement; }
void setStatement(Statement* value);
bool isImplemented() const { return implemented; }
void setImplemented(bool value) { implemented = value; }
@ -212,18 +206,9 @@ namespace Jrd
const Firebird::Array<NestConst<Parameter> >& getOutputFields() const { return outputFields; }
Firebird::Array<NestConst<Parameter> >& getOutputFields() { return outputFields; }
bool hasData() const { return name.hasData(); }
void parseBlr(thread_db* tdbb, CompilerScratch* csb, bid* blob_id, bid* blobDbg);
void parseMessages(thread_db* tdbb, CompilerScratch* csb, Firebird::BlrReader blrReader);
bool isUsed() const
{
return getUseCount() != 0;
}
int getUseCount() const;
virtual void releaseFormat()
{
}
@ -236,9 +221,6 @@ namespace Jrd
{
}
void adjust_dependencies();
void sharedCheckLock(thread_db* tdbb);
void sharedCheckUnlock(thread_db* tdbb);
void releaseLocks(thread_db* tdbb);
@ -247,12 +229,11 @@ namespace Jrd
virtual SLONG getSclType() const = 0;
virtual bool checkCache(thread_db* tdbb) const = 0;
public:
RoutinePermanent* permanent; // Permanent part of data
private:
USHORT id; // routine ID
QualifiedName name; // routine name
MetaName securityName; // security class name
Statement* statement; // compiled routine statement
bool subRoutine; // Is this a subroutine?
bool implemented; // Is the packaged routine missing the body/entrypoint?
bool defined; // UDF has its implementation module available
USHORT defaultCount; // default input arguments
@ -262,7 +243,6 @@ namespace Jrd
Firebird::Array<NestConst<Parameter> > outputFields; // array of field blocks
protected:
virtual bool reload(thread_db* tdbb) = 0;
public:
@ -270,15 +250,6 @@ namespace Jrd
StartupBarrier startup;
public:
SSHORT intUseCount; // number of routines compiled with routine, set and
// used internally in the clear_cache() routine
// no code should rely on value of this field
// (it will usually be 0)
USHORT alterCount; // No. of times the routine was altered
Firebird::AutoPtr<ExistenceLock> existenceLock; // existence lock, if any
MetaName owner;
Jrd::UserId* invoker; // Invoker ID
};
}

View File

@ -93,7 +93,6 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att,
// Calculate relation-level statistics
temp.clear();
MetadataCache* mdc = att->att_database->dbb_mdc;
// This loop assumes that base array is smaller than new one
RelCounters::iterator base_cnts = rel_counts.begin();
@ -113,8 +112,8 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att,
TraceCounts traceCounts;
traceCounts.trc_relation_id = rel_id;
traceCounts.trc_counters = base_cnts->getCounterVector();
jrd_rel* relation = mdc->getRelation(att, rel_id);
traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL;
auto relation = att->att_database->dbb_mdc->lookupRelation(rel_id);
traceCounts.trc_relation_name = relation ? relation->c_name() : NULL;
temp.add(traceCounts);
}
@ -127,8 +126,8 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att,
TraceCounts traceCounts;
traceCounts.trc_relation_id = rel_id;
traceCounts.trc_counters = new_cnts->getCounterVector();
jrd_rel* relation = mdc->getRelation(att, rel_id);
traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL;
auto relation = att->att_database->dbb_mdc->lookupRelation(rel_id);
traceCounts.trc_relation_name = relation ? relation->c_name() : NULL;
temp.add(traceCounts);
}
};
@ -140,7 +139,7 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att,
}
RuntimeStatistics::Accumulator::Accumulator(thread_db* tdbb, const jrd_rel* relation, StatType type)
: m_tdbb(tdbb), m_type(type), m_id(relation->rel_id), m_counter(0)
: m_tdbb(tdbb), m_type(type), m_id(relation->getId()), m_counter(0)
{}
RuntimeStatistics::Accumulator::~Accumulator()

View File

@ -79,7 +79,7 @@ namespace Jrd
{
public:
VerbAction()
: vct_next(NULL), vct_relation(NULL), vct_records(NULL), vct_undo(NULL)
: vct_next(NULL), vct_records(NULL), vct_undo(NULL)
{}
~VerbAction()

View File

@ -67,7 +67,6 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
requests(*p),
externalList(*p),
accessList(*p),
resources(*p, false),
triggerName(*p),
triggerInvoker(NULL),
parentStatement(NULL),
@ -76,7 +75,8 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
localTables(*p),
invariants(*p),
blr(*p),
mapFieldInfo(*p)
mapFieldInfo(*p),
resources(csb->csb_resources)
{
try
{
@ -94,8 +94,8 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
mapFieldInfo.takeOwnership(csb->csb_map_field_info);
// Take out existence locks on resources used in statement.
resources.transferResources(tdbb, csb->csb_resources);
// versioned metadata support
loadResources(tdbb);
impureSize = csb->csb_impure;
@ -120,6 +120,8 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
auto tail = csb->csb_rpt.begin();
const auto* const streams_end = tail + csb->csb_n_stream;
// Add more strems info (format, relation, procedure) to rpbsSetup
// in order to check format match when mdc version grows !!!!!!!!!!!!!!!!!!!!!!!!
for (auto rpb = rpbsSetup.begin(); tail < streams_end; ++rpb, ++tail)
{
// fetch input stream for update if all booleans matched against indices
@ -155,6 +157,7 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
csb->outerMessagesMap.clear();
csb->outerVarsMap.clear();
csb->csb_rpt.free();
csb->csb_resources = nullptr;
}
catch (Exception&)
{
@ -169,6 +172,34 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
}
}
void Statement::loadResources(thread_db* tdbb)
{
const MdcVersion currentMdcVersion = tdbb->getDatabase()->dbb_mdc->getVersion();
if ((!latestVersion) || (latestVersion->version != currentMdcVersion))
{
// Also check for changed streams from known sources
if (!streamsFormatCompare(tdbb))
ERR_post(Arg::Gds(isc_random) << "Statement format outdated, need to be reprepared");
// OK, format of data sources remained the same, we can update version of cached objects in current request
const FB_SIZE_T resourceCount = latestVersion ? latestVersion->getCapacity() :
resources->charSets.getCount() + resources->relations.getCount() + resources->procedures.getCount() +
resources->functions.getCount() + resources->triggers.getCount();
latestVersion = FB_NEW_RPT(*pool, resourceCount) VersionedObjects(resourceCount, currentMdcVersion);
resources->transfer(tdbb, latestVersion);
}
}
void Resources::transfer(thread_db* tdbb, VersionedObjects* to)
{
charSets.transfer(tdbb, to);
relations.transfer(tdbb, to);
procedures.transfer(tdbb, to);
functions.transfer(tdbb, to);
triggers.transfer(tdbb, to);
}
// Turn a parsed scratch into a statement.
Statement* Statement::makeStatement(thread_db* tdbb, CompilerScratch* csb, bool internalFlag,
std::function<void ()> beforeCsbRelease)
@ -188,8 +219,6 @@ Statement* Statement::makeStatement(thread_db* tdbb, CompilerScratch* csb, bool
fb_assert(!"wrong pool in makeStatement");
found:
Request* const old_request = tdbb->getRequest();
tdbb->setRequest(NULL);
const auto attachment = tdbb->getAttachment();
const auto old_request = tdbb->getRequest();
@ -401,7 +430,7 @@ Request* Statement::findRequest(thread_db* tdbb, bool unique)
return clone;
}
Request* Statement::getRequest(thread_db* tdbb, USHORT level)
Request* Statement::getRequest(thread_db* tdbb, USHORT level, bool systemRequest)
{
SET_TDBB(tdbb);
@ -409,21 +438,31 @@ Request* Statement::getRequest(thread_db* tdbb, USHORT level)
Database* const dbb = tdbb->getDatabase();
fb_assert(dbb);
if (level < requests.getCount() && requests[level])
return requests[level];
if (level >= requests.getCount() || !requests[level])
{
// Create the request.
AutoMemoryPool reqPool(MemoryPool::createPool(pool));
auto request = FB_NEW_POOL(*reqPool) Request(reqPool, attachment, this);
// MemoryStats* const parentStats = (flags & FLAG_INTERNAL) ?
// &dbb->dbb_memory_stats : &attachment->att_memory_stats;
{ // guard scope
MutexLockGuard guard(requestsGrow, FB_FUNCTION);
// Create the request.
const auto request = FB_NEW_POOL(*pool) Request(attachment, this, &dbb->dbb_memory_stats);
if (level >= requests.getCount() || !requests[level])
{
requests.grow(level + 1);
requests[level] = request;
request = nullptr;
}
}
if (level == 0)
pool->setStatsGroup(request->req_memory_stats);
requests.grow(level + 1);
requests[level] = request;
if (request)
delete request;
}
const auto request = requests[level];
if (!(systemRequest && request->resources))
loadResources(tdbb);
request->resources = latestVersion;
return request;
}
@ -442,7 +481,7 @@ void Statement::verifyAccess(thread_db* tdbb)
for (ExternalAccess* item = external.begin(); item != external.end(); ++item)
{
HazardPtr<Routine> routine(tdbb);
Routine* routine = nullptr;
int aclType;
if (item->exa_action == ExternalAccess::exa_procedure)
@ -479,24 +518,24 @@ void Statement::verifyAccess(thread_db* tdbb)
MetaName userName = item->user;
if (item->exa_view_id)
{
jrd_rel* view = MetadataCache::lookup_relation_id(tdbb, item->exa_view_id, false);
if (view && (view->rel_flags & REL_sql_relation))
auto view = MetadataCache::lookupRelation(tdbb, item->exa_view_id);
if (view && (view->getId() >= USER_DEF_REL_INIT_ID))
userName = view->rel_owner_name;
}
switch (item->exa_action)
{
case ExternalAccess::exa_insert:
verifyTriggerAccess(tdbb, relation, relation->rel_pre_store, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_post_store, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_PRE_STORE], userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_POST_STORE], userName);
break;
case ExternalAccess::exa_update:
verifyTriggerAccess(tdbb, relation, relation->rel_pre_modify, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_post_modify, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_PRE_MODIFY], userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_POST_MODIFY], userName);
break;
case ExternalAccess::exa_delete:
verifyTriggerAccess(tdbb, relation, relation->rel_pre_erase, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_post_erase, userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_PRE_ERASE], userName);
verifyTriggerAccess(tdbb, relation, relation->rel_triggers[TRIGGER_POST_ERASE], userName);
break;
default:
fb_assert(false);
@ -515,8 +554,8 @@ void Statement::verifyAccess(thread_db* tdbb)
if (access.acc_ss_rel_id)
{
jrd_rel* view = MetadataCache::lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
if (view && (view->rel_flags & REL_sql_relation))
auto view = MetadataCache::lookupRelation(tdbb, access.acc_ss_rel_id);
if (view && (view->getId() >= USER_DEF_REL_INIT_ID))
userName = view->rel_owner_name;
}
@ -583,8 +622,8 @@ void Statement::verifyAccess(thread_db* tdbb)
if (access->acc_ss_rel_id)
{
jrd_rel* view = MetadataCache::lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
if (view && (view->rel_flags & REL_sql_relation))
auto view = MetadataCache::lookupRelation(tdbb, access->acc_ss_rel_id);
if (view && (view->getId() >= USER_DEF_REL_INIT_ID))
userName = view->rel_owner_name;
}
@ -614,7 +653,7 @@ void Statement::release(thread_db* tdbb)
// Release existence locks on references.
resources.releaseResources(tdbb);
// resources.releaseResources(tdbb); !!!!!!!!!!!!!!! place to release
for (Request** instance = requests.begin(); instance != requests.end(); ++instance)
{
@ -630,8 +669,6 @@ void Statement::release(thread_db* tdbb)
if (attachment)
{
// !!!!!!!!!!!!!!!! need to walk all attachments in database
// or change att_statements to dbb_statements
if (!attachment->att_statements.findAndRemove(this))
fb_assert(false);
}
@ -659,19 +696,15 @@ string Statement::getPlan(thread_db* tdbb, bool detailed) const
// Check that we have enough rights to access all resources this list of triggers touches.
void Statement::verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelation,
TrigVector* triggers, MetaName userName)
const Triggers& triggers, MetaName userName)
{
if (!triggers)
return;
SET_TDBB(tdbb);
for (FB_SIZE_T i = 0; i < triggers->getCount(tdbb); i++)
for (auto t : triggers)
{
HazardPtr<Trigger> t(tdbb);
if (!triggers->load(tdbb, i, t))
continue;
t->compile(tdbb);
if (!t->statement)
continue;
@ -691,12 +724,12 @@ void Statement::verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelatio
if (!(ownerRelation->rel_flags & REL_system))
{
if (access->acc_type == obj_relations &&
(ownerRelation->rel_name == access->acc_name))
(ownerRelation->getName() == access->acc_name))
{
continue;
}
if (access->acc_type == obj_column &&
(ownerRelation->rel_name == access->acc_r_name))
(ownerRelation->getName() == access->acc_r_name))
{
continue;
}
@ -705,8 +738,8 @@ void Statement::verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelatio
// a direct access to an object from this trigger
if (access->acc_ss_rel_id)
{
jrd_rel* view = MetadataCache::lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
if (view && (view->rel_flags & REL_sql_relation))
auto view = MetadataCache::lookupRelation(tdbb, access->acc_ss_rel_id);
if (view && (view->getId() >= USER_DEF_REL_INIT_ID))
userName = view->rel_owner_name;
}
else if (t->ssDefiner.specified && t->ssDefiner.value)
@ -726,17 +759,13 @@ void Statement::verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelatio
// Invoke buildExternalAccess for triggers in vector
inline void Statement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list,
TrigVector* tvec, const MetaName& user)
const Triggers& tvec, const MetaName& user)
{
if (!tvec)
return;
for (FB_SIZE_T i = 0; i < tvec->getCount(tdbb); i++)
for (auto t : tvec)
{
HazardPtr<Trigger> t(tdbb);
if (!tvec->load(tdbb, i, t))
continue;
t->compile(tdbb);
if (t->statement)
{
@ -757,7 +786,7 @@ void Statement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, c
// Add externals recursively
if (item->exa_action == ExternalAccess::exa_procedure)
{
HazardPtr<jrd_prc> procedure = MetadataCache::lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
auto procedure = MetadataCache::lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
if (procedure && procedure->getStatement())
{
item->user = procedure->invoker ? MetaName(procedure->invoker->getUserName()) : user;
@ -769,7 +798,7 @@ void Statement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, c
}
else if (item->exa_action == ExternalAccess::exa_function)
{
Function* function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
auto function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
if (function && function->getStatement())
{
item->user = function->invoker ? MetaName(function->invoker->getUserName()) : user;
@ -782,36 +811,35 @@ void Statement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, c
else
{
jrd_rel* relation = MetadataCache::lookup_relation_id(tdbb, item->exa_rel_id, false);
if (!relation)
continue;
RefPtr<TrigVector> vec1, vec2;
Triggers *vec1, *vec2;
switch (item->exa_action)
{
case ExternalAccess::exa_insert:
vec1 = relation->rel_pre_store;
vec2 = relation->rel_post_store;
vec1 = &relation->rel_triggers[TRIGGER_PRE_STORE];
vec2 = &relation->rel_triggers[TRIGGER_POST_STORE];
break;
case ExternalAccess::exa_update:
vec1 = relation->rel_pre_modify;
vec2 = relation->rel_post_modify;
vec1 = &relation->rel_triggers[TRIGGER_PRE_MODIFY];
vec2 = &relation->rel_triggers[TRIGGER_POST_MODIFY];
break;
case ExternalAccess::exa_delete:
vec1 = relation->rel_pre_erase;
vec2 = relation->rel_post_erase;
vec1 = &relation->rel_triggers[TRIGGER_PRE_ERASE];
vec2 = &relation->rel_triggers[TRIGGER_POST_ERASE];
break;
default:
fb_assert(false);
continue; // should never happen, silence the compiler
}
item->user = relation->rel_ss_definer.orElse(false) ? relation->rel_owner_name : user;
item->user = relation->rel_ss_definer.orElse(false) ? relation->rel_perm->rel_owner_name : user;
if (list.find(*item, i))
continue;
list.insert(i, *item);
triggersExternalAccess(tdbb, list, vec1, item->user);
triggersExternalAccess(tdbb, list, vec2, item->user);
triggersExternalAccess(tdbb, list, *vec1, item->user);
triggersExternalAccess(tdbb, list, *vec2, item->user);
}
}
}
@ -859,32 +887,6 @@ template <typename T> static void makeSubRoutines(thread_db* tdbb, Statement* st
}
}
Request::Request(Attachment* attachment, /*const*/ Statement* aStatement,
Firebird::MemoryStats* parent_stats)
: statement(aStatement),
req_pool(statement->pool),
req_memory_stats(parent_stats),
req_blobs(req_pool),
req_stats(*req_pool),
req_base_stats(*req_pool),
req_ext_stmt(NULL),
req_cursors(*req_pool),
req_ext_resultset(NULL),
req_timeout(0),
req_domain_validation(NULL),
req_sorts(*req_pool),
req_rpb(*req_pool),
impureArea(*req_pool),
req_auto_trans(*req_pool)
{
fb_assert(statement);
setAttachment(attachment);
req_rpb = statement->rpbsSetup;
impureArea.grow(statement->impureSize);
}
bool Request::hasInternalStatement() const
{
return statement->flags & Statement::FLAG_INTERNAL;
@ -912,33 +914,6 @@ StmtNumber Request::getRequestId() const
return req_id;
}
Request::Request(Firebird::AutoMemoryPool& pool, Attachment* attachment, /*const*/ Statement* aStatement)
: statement(aStatement),
req_pool(pool),
req_memory_stats(&aStatement->pool->getStatsGroup()),
req_blobs(req_pool),
req_stats(*req_pool),
req_base_stats(*req_pool),
req_ext_stmt(NULL),
req_cursors(*req_pool),
req_ext_resultset(NULL),
req_timeout(0),
req_domain_validation(NULL),
req_auto_trans(*req_pool),
req_sorts(*req_pool),
req_rpb(*req_pool),
impureArea(*req_pool)
{
fb_assert(statement);
setAttachment(attachment);
req_rpb = statement->rpbsSetup;
impureArea.grow(statement->impureSize);
pool->setStatsGroup(req_memory_stats);
pool.release();
}
#ifdef DEV_BUILD
// Function is designed to be called from debugger to print subtree of current execution node

View File

@ -74,19 +74,25 @@ public:
bool isActive() const;
Request* findRequest(thread_db* tdbb, bool unique = false);
Request* getRequest(thread_db* tdbb, USHORT level);
Request* getRequest(thread_db* tdbb, USHORT level, bool systemRequest = false);
void verifyAccess(thread_db* tdbb);
void release(thread_db* tdbb);
Firebird::string getPlan(thread_db* tdbb, bool detailed) const;
const Resources* getResources()
{
return resources;
}
private:
static void verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelation, TrigVector* triggers,
static void verifyTriggerAccess(thread_db* tdbb, const jrd_rel* ownerRelation, const Triggers& triggers,
MetaName userName);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, TrigVector* tvec, const MetaName &user);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, const Triggers& tvec, const MetaName &user);
void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, const MetaName& user);
void loadResources(thread_db* tdbb);
bool streamsFormatCompare(thread_db* tdbb);
public:
MemoryPool* pool;
unsigned flags; // statement flags
@ -94,11 +100,11 @@ public:
ULONG impureSize; // Size of impure area
mutable StmtNumber id; // statement identifier
USHORT charSetId; // client character set (CS_METADATA for internal statements)
Firebird::Array<record_param> rpbsSetup;
Firebird::Array<RecordParameter> rpbsSetup;
Firebird::Array<Request*> requests; // vector of requests
Firebird::Mutex requestsGrow; // vector of requests protection when added new element
ExternalAccessList externalList; // Access to procedures/triggers to be checked
AccessItemList accessList; // Access items to be checked
//ResourceList resources; // Resources (relations and indices)
const jrd_prc* procedure; // procedure, if any
const Function* function; // function, if any
MetaName triggerName; // name of request (trigger), if any
@ -114,8 +120,8 @@ public:
MapFieldInfo mapFieldInfo; // Map field name to field info
private:
Resources resources;
Firebird::RefPtr<VersionedObjects> latestVersion;
Resources* resources; // Resources (relations, routines, etc.)
Firebird::RefPtr<VersionedObjects> latestVersion; // want std::atomic<std::shared_ptr> or mutex is needed
};

View File

@ -5315,7 +5315,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV
if (!relation)
(Arg::Gds(isc_relnotdef) << Arg::Str(relName)).raise();
relId = relation->rel_id;
relId = relation->getId();
}
else
{
@ -5892,7 +5892,7 @@ dsc* evlPosition(thread_db* tdbb, const SysFunction* function, const NestValueAr
// we'll use the collation from the second string
const USHORT ttype = value2->getTextType();
HazardPtr<TextType> tt = INTL_texttype_lookup(tdbb, ttype);
TextType* tt = INTL_texttype_lookup(tdbb, ttype);
CharSet* cs = tt->getCharSet();
const UCHAR canonicalWidth = tt->getCanonicalWidth();
@ -6076,7 +6076,7 @@ dsc* evlReplace(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
}
const USHORT ttype = values[0]->getTextType();
HazardPtr<TextType> tt = INTL_texttype_lookup(tdbb, ttype);
TextType* tt = INTL_texttype_lookup(tdbb, ttype);
CharSet* cs = tt->getCharSet();
const UCHAR canonicalWidth = tt->getCanonicalWidth();

View File

@ -580,7 +580,7 @@ void UserManagement::list(IUser* u, unsigned cachePosition)
RecordBuffer* UserManagement::getList(thread_db* tdbb, jrd_rel* relation)
{
fb_assert(relation);
fb_assert(relation->rel_id == rel_sec_user_attributes || relation->rel_id == rel_sec_users);
fb_assert(relation->getId() == rel_sec_user_attributes || relation->getId() == rel_sec_users);
RecordBuffer* recordBuffer = getData(relation);
if (recordBuffer)

View File

@ -59,7 +59,7 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb)
dsc desc;
lck_t lock_type;
if (relation->rel_id == rel_mon_attachments)
if (relation->getId() == rel_mon_attachments)
{
// Get attachment id
if (!EVL_field(relation, rpb->rpb_record, f_mon_att_id, &desc))
@ -75,7 +75,7 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb)
lock_type = LCK_attachment;
}
else if (relation->rel_id == rel_mon_statements)
else if (relation->getId() == rel_mon_statements)
{
// Get attachment id
if (!EVL_field(relation, rpb->rpb_record, f_mon_stmt_att_id, &desc))

View File

@ -122,8 +122,6 @@ void WorkerStableAttachment::fini()
Monitoring::cleanupAttachment(tdbb);
attachment->releaseLocks(tdbb);
LCK_fini(tdbb, LCK_OWNER_attachment);
attachment->releaseRelations(tdbb);
}
destroy(attachment);

View File

@ -73,6 +73,7 @@
#include "../common/dsc_proto.h"
#include "../common/classes/array.h"
#include "../common/classes/VaryStr.h"
#include "../jrd/Statement.h"
using namespace Jrd;
using namespace Firebird;
@ -80,15 +81,9 @@ using namespace Firebird;
typedef Ods::blob_page blob_page;
static ArrayField* alloc_array(jrd_tra*, Ods::InternalArrayDesc*);
//static blb* allocate_blob(thread_db*, jrd_tra*);
static ISC_STATUS blob_filter(USHORT, BlobControl*);
//static blb* copy_blob(thread_db*, const bid*, bid*, USHORT, const UCHAR*, USHORT);
//static void delete_blob(thread_db*, blb*, ULONG);
//static void delete_blob_id(thread_db*, const bid*, ULONG, jrd_rel*);
static ArrayField* find_array(jrd_tra*, const bid*);
static BlobFilter* find_filter(thread_db*, SSHORT, SSHORT);
//static blob_page* get_next_page(thread_db*, blb*, WIN *);
//static void insert_page(thread_db*, blb*);
static void move_from_string(Jrd::thread_db*, const dsc*, dsc*, jrd_rel*, Record*, USHORT);
static void move_to_string(Jrd::thread_db*, dsc*, dsc*);
static void slice_callback(array_slice*, ULONG, dsc*);
@ -469,7 +464,7 @@ void BLB_garbage_collect(thread_db* tdbb,
const bid* blob = (bid*) desc.dsc_address;
if (!blob->isEmpty())
{
if (blob->bid_internal.bid_relation_id == relation->rel_id)
if (blob->bid_internal.bid_relation_id == relation->getId())
{
const RecordNumber number = blob->get_permanent_number();
bmGoing.set(number.getValue());
@ -482,7 +477,7 @@ void BLB_garbage_collect(thread_db* tdbb,
// ignore it. To be reconsider latter based on real user reports.
// The same about staying blob few lines below
gds__log("going blob (%ld:%ld) is not owned by relation (id = %d), ignored",
blob->bid_quad.bid_quad_high, blob->bid_quad.bid_quad_low, relation->rel_id);
blob->bid_quad.bid_quad_high, blob->bid_quad.bid_quad_low, relation->getId());
}
}
}
@ -508,7 +503,7 @@ void BLB_garbage_collect(thread_db* tdbb,
const bid* blob = (bid*) desc.dsc_address;
if (!blob->isEmpty())
{
if (blob->bid_internal.bid_relation_id == relation->rel_id)
if (blob->bid_internal.bid_relation_id == relation->getId())
{
const RecordNumber number = blob->get_permanent_number();
if (bmGoing.test(number.getValue()))
@ -521,7 +516,7 @@ void BLB_garbage_collect(thread_db* tdbb,
else
{
gds__log("staying blob (%ld:%ld) is not owned by relation (id = %d), ignored",
blob->bid_quad.bid_quad_high, blob->bid_quad.bid_quad_low, relation->rel_id);
blob->bid_quad.bid_quad_high, blob->bid_quad.bid_quad_low, relation->getId());
}
}
}
@ -535,7 +530,7 @@ void BLB_garbage_collect(thread_db* tdbb,
const FB_UINT64 id = bmGoing.current();
bid blob;
blob.set_permanent(relation->rel_id, RecordNumber(id));
blob.set_permanent(relation->getId(), RecordNumber(id));
blb::delete_blob_id(tdbb, &blob, prior_page, relation);
} while (bmGoing.getNext());
@ -1045,7 +1040,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc,
// We should not materialize the blob if the destination field
// stream (nod_union, for example) doesn't have a relation.
const bool simpleMove = (relation == NULL);
const bool simpleMove = !relation;
// Use local copy of source blob id to not change contents of from_desc in
// a case when it points to materialized temporary blob (see below for
@ -1102,11 +1097,11 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc,
Request* request = tdbb->getRequest();
if (relation->isVirtual()) {
if (relation->rel_perm->isVirtual()) {
ERR_post(Arg::Gds(isc_read_only));
}
RelationPages* relPages = relation->getPages(tdbb);
RelationPages* relPages = relation->rel_perm->getPages(tdbb);
// If either the source value is null or the blob id itself is null
// (all zeros), then the blob is null.
@ -1125,7 +1120,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc,
// If the target is a view, this must be from a view update trigger.
// Just pass the blob id thru.
if (relation->rel_view_rse)
if (relation->isView())
{
// But if the sub_type or charset is different, create a new blob.
if (DTYPE_IS_BLOB_OR_QUAD(from_desc->dsc_dtype) &&
@ -1259,7 +1254,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc,
if (bulk)
blob->blb_flags |= BLB_bulk;
destination->set_permanent(relation->rel_id, DPM_store_blob(tdbb, blob, record));
destination->set_permanent(relation->getId(), DPM_store_blob(tdbb, blob, relation, record));
// This is the only place in the engine where blobs are materialized
// If new places appear code below should transform to common sub-routine
if (materialized_blob)
@ -1450,7 +1445,7 @@ blb* blb::open2(thread_db* tdbb,
ERR_post(Arg::Gds(isc_bad_segstr_id));
blob->blb_pg_space_id = relation->getPages(tdbb)->rel_pg_space_id;
DPM_get_blob(tdbb, blob, relation.getPointer(), blobId.get_permanent_number(), false, 0);
DPM_get_blob(tdbb, blob, relation, blobId.get_permanent_number(), false, 0);
#ifdef CHECK_BLOB_FIELD_ACCESS_FOR_SELECT
if (!relation->isSystem() && blob->blb_fld_id < relation->rel_fields->count())
@ -1753,15 +1748,12 @@ void blb::put_slice(thread_db* tdbb,
SSHORT n;
if (info.sdl_info_field.length()) {
n = MET_lookup_field(tdbb, relation.getPointer(), info.sdl_info_field);
n = MET_lookup_field(tdbb, relation, info.sdl_info_field);
}
else {
n = info.sdl_info_fid;
}
// Make sure relation is scanned
MET_scan_relation(tdbb, relation);
jrd_fld* field;
if (n < 0 || !(field = MET_get_field(relation, n))) {
IBERROR(197); // msg 197 field for array not known
@ -2273,7 +2265,7 @@ void blb::delete_blob_id(thread_db* tdbb, const bid* blob_id, ULONG prior_page,
if (blob_id->isEmpty())
return;
if (blob_id->bid_internal.bid_relation_id != relation->rel_id)
if (blob_id->bid_internal.bid_relation_id != relation->getId())
CORRUPT(200); // msg 200 invalid blob id
// Fetch blob

View File

@ -38,6 +38,7 @@
#include "firebird/Interface.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/dsc.h"
#include "../jrd/Resource.h"
namespace Ods
{
@ -51,6 +52,7 @@ namespace Jrd
class Attachment;
class BlobControl;
class jrd_rel;
class RelationPermanent;
class Request;
class jrd_tra;
class vcl;
@ -102,22 +104,22 @@ public:
bool BLB_close(thread_db*);
static blb* create(thread_db*, jrd_tra*, bid*);
static blb* create2(thread_db*, jrd_tra*, bid*, USHORT, const UCHAR*, bool = false);
static Jrd::blb* get_array(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, Ods::InternalArrayDesc*);
static blb* get_array(thread_db*, jrd_tra*, const bid*, Ods::InternalArrayDesc*);
ULONG BLB_get_data(thread_db*, UCHAR*, SLONG, bool = true);
USHORT BLB_get_segment(thread_db*, void*, USHORT);
static SLONG get_slice(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, const UCHAR*, USHORT,
static SLONG get_slice(thread_db*, jrd_tra*, const bid*, const UCHAR*, USHORT,
const UCHAR*, SLONG, UCHAR*);
SLONG BLB_lseek(USHORT, SLONG);
static void move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, jrd_rel* relation = nullptr, Record* record = nullptr, USHORT fieldId = 0, bool bulk = false);
static void move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, jrd_rel* = nullptr, Record* record = nullptr, USHORT fieldId = 0, bool bulk = false);
static blb* open(thread_db*, jrd_tra*, const bid*);
static blb* open2(thread_db*, jrd_tra*, const bid*, USHORT, const UCHAR*, bool = false);
void BLB_put_data(thread_db*, const UCHAR*, SLONG);
void BLB_put_segment(thread_db*, const void*, USHORT);
static void put_slice(thread_db*, jrd_tra*, bid*, const UCHAR*, USHORT, const UCHAR*, SLONG, UCHAR*);
static void release_array(Jrd::ArrayField*);
static void scalar(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::bid*, USHORT, const SLONG*, Jrd::impure_value*);
static void release_array(ArrayField*);
static void scalar(thread_db*, jrd_tra*, const bid*, USHORT, const SLONG*, impure_value*);
static void delete_blob_id(thread_db*, const bid*, ULONG, jrd_rel*);
static void delete_blob_id(thread_db*, const bid*, ULONG, Jrd::jrd_rel*);
void fromPageHeader(const Ods::blh* header);
void toPageHeader(Ods::blh* header) const;
void getFromPage(USHORT length, const UCHAR* data);

View File

@ -282,7 +282,7 @@ void IndexErrorContext::raise(thread_db* tdbb, idx_e result, Record* record)
if (result == idx_e_conversion || result == idx_e_interrupt)
ERR_punt();
const MetaName& relationName = isLocationDefined ? m_location.relation->rel_name : m_relation->rel_name;
const MetaName& relationName = isLocationDefined ? m_location.relation->getName() : m_relation->getName();
const USHORT indexId = isLocationDefined ? m_location.indexId : m_index->idx_id;
MetaName indexName(m_indexName), constraintName;
@ -1417,14 +1417,14 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id
error.value()[1] == isc_expression_eval_index))
{
MetaName indexName;
MetadataCache::lookup_index(tdbb, indexName, relation->rel_name, idx->idx_id + 1);
MetadataCache::lookup_index(tdbb, indexName, relation->getName(), idx->idx_id + 1);
if (indexName.isEmpty())
indexName = "***unknown***";
error.prepend(Arg::Gds(isc_expression_eval_index) <<
Arg::Str(indexName) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
error.copyTo(tdbb->tdbb_status_vector);
@ -3581,7 +3581,7 @@ static ULONG fast_load(thread_db* tdbb,
// only for debug) so the id is actually redundant.
btree_page* bucket = (btree_page*) DPM_allocate(tdbb, &leafLevel->window);
bucket->btr_header.pag_type = pag_index;
bucket->btr_relation = relation->rel_id;
bucket->btr_relation = relation->getId();
bucket->btr_id = (UCHAR)(idx->idx_id % 256);
bucket->btr_level = 0;
bucket->btr_length = BTR_SIZE;
@ -3936,7 +3936,7 @@ static ULONG fast_load(thread_db* tdbb,
currLevel->bucket = bucket = (btree_page*) DPM_allocate(tdbb, window);
bucket->btr_header.pag_type = pag_index;
bucket->btr_relation = relation->rel_id;
bucket->btr_relation = relation->getId();
bucket->btr_id = (UCHAR)(idx->idx_id % 256);
fb_assert(level <= MAX_UCHAR);
bucket->btr_level = (UCHAR) level;
@ -4265,7 +4265,7 @@ static ULONG fast_load(thread_db* tdbb,
if (window)
{
delete_tree(tdbb, relation->rel_id, idx->idx_id,
delete_tree(tdbb, relation->getId(), idx->idx_id,
window->win_page, PageNumber(window->win_page.getPageSpaceID(), 0));
}
@ -4295,7 +4295,7 @@ static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const jrd_rel*
if ((window->win_page = relPages->rel_index_root) == 0)
{
if (relation->rel_id == 0)
if (relation->getId() == 0)
return NULL;
DPM_scan_pages(tdbb);
@ -6201,13 +6201,6 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re
string key;
fb_assert(relation && idx && record);
jrd_rel* wrk = MET_scan_relation(tdbb, relation->rel_id);
if (!wrk)
{
key.printf("(target relation %s deleted)", relation->c_name());
return key;
}
relation = wrk;
const FB_SIZE_T MAX_KEY_STRING_LEN = 250;
string value;

View File

@ -29,7 +29,7 @@
#include "../jrd/req.h"
#include "../jrd/exe.h"
void BTR_all(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::IndexDescList&, Jrd::RelationPages*);
void BTR_all(Jrd::thread_db*, Jrd::RelationPermanent*, Jrd::IndexDescList&, Jrd::RelationPages*);
void BTR_complement_key(Jrd::temporary_key*);
void BTR_create(Jrd::thread_db*, Jrd::IndexCreation&, Jrd::SelectivityList&);
bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT);

View File

@ -5447,49 +5447,6 @@ void BCBHashTable::remove(BufferDesc* bdb)
#ifdef HASH_USE_CDS_LIST
/// class ListNodeAllocator<T>
class InitPool
{
public:
explicit InitPool(MemoryPool&)
{
m_pool = InitCDS::createPool();
m_pool->setStatsGroup(m_stats);
}
~InitPool()
{
// m_pool will be deleted by InitCDS dtor after cds termination
// some memory could still be not freed until that moment
#ifdef DEBUG_CDS_MEMORY
char str[256];
sprintf(str, "CCH list's common pool stats:\n"
" usage = %llu\n"
" mapping = %llu\n"
" max usage = %llu\n"
" max mapping = %llu\n"
"\n",
m_stats.getCurrentUsage(),
m_stats.getCurrentMapping(),
m_stats.getMaximumUsage(),
m_stats.getMaximumMapping()
);
gds__log(str);
#endif
}
void* alloc(size_t size)
{
return m_pool->allocate(size ALLOC_ARGS);
}
private:
MemoryPool* m_pool;
MemoryStats m_stats;
};
static InitInstance<InitPool> initPool;
@ -5506,4 +5463,9 @@ void ListNodeAllocator<T>::deallocate(T* p, std::size_t /* n */)
MemoryPool::globalFree(p);
}
void suspend()
{
cds::backoff::pause();
}
#endif // HASH_USE_CDS_LIST

View File

@ -174,9 +174,9 @@ Statement* CMP_compile(thread_db* tdbb, const UCHAR* blr, ULONG blrLength, bool
"\t%2d - view_stream: %2d; alias: %s; relation: %s; procedure: %s; view: %s\n",
i, s.csb_view_stream,
(s.csb_alias ? s.csb_alias->c_str() : ""),
(s.csb_relation ? s.csb_relation->rel_name.c_str() : ""),
(s.csb_procedure ? s.csb_procedure->getName().toString().c_str() : ""),
(s.csb_view ? s.csb_view->rel_name.c_str() : ""));
(s.csb_relation ? s.csb_relation()->getName().c_str() : ""),
(s.csb_procedure ? s.csb_procedure()->getName().toString().c_str() : ""),
(s.csb_view ? s.csb_view->getName().c_str() : ""));
}
cmp_trace("\n%s\n", csb->csb_dump.c_str());
@ -264,9 +264,9 @@ const Format* CMP_format(thread_db* tdbb, CompilerScratch* csb, StreamType strea
if (!tail->csb_format)
{
if (tail->csb_relation)
tail->csb_format = MET_current(tdbb, tail->csb_relation);
tail->csb_format = MET_current(tdbb, tail->csb_relation(tdbb));
else if (tail->csb_procedure)
tail->csb_format = tail->csb_procedure->prc_record_format;
tail->csb_format = tail->csb_procedure(tdbb)->prc_record_format;
//// TODO: LocalTableSourceNode
else
IBERROR(222); // msg 222 bad blr - invalid stream
@ -375,7 +375,7 @@ ItemInfo* CMP_pass2_validation(thread_db* tdbb, CompilerScratch* csb, const Item
}
void CMP_post_procedure_access(thread_db* tdbb, CompilerScratch* csb, jrd_prc* procedure)
void CMP_post_procedure_access(thread_db* tdbb, CompilerScratch* csb, Rsc::Proc proc)
{
/**************************************
*
@ -399,21 +399,21 @@ void CMP_post_procedure_access(thread_db* tdbb, CompilerScratch* csb, jrd_prc* p
return;
// this request must have EXECUTE permission on the stored procedure
if (procedure->getName().package.isEmpty())
if (proc()->getName().package.isEmpty())
{
CMP_post_access(tdbb, csb, procedure->getSecurityName(),
(csb->csb_view ? csb->csb_view->rel_id : 0),
SCL_execute, obj_procedures, procedure->getName().identifier);
CMP_post_access(tdbb, csb, proc()->getSecurityName(),
(csb->csb_view ? csb->csb_view()->getId() : 0),
SCL_execute, obj_procedures, proc()->getName().identifier);
}
else
{
CMP_post_access(tdbb, csb, procedure->getSecurityName(),
(csb->csb_view ? csb->csb_view->rel_id : 0),
SCL_execute, obj_packages, procedure->getName().package);
CMP_post_access(tdbb, csb, proc()->getSecurityName(),
(csb->csb_view ? csb->csb_view()->getId() : 0),
SCL_execute, obj_packages, proc()->getName().package);
}
// Add the procedure to list of external objects accessed
ExternalAccess temp(ExternalAccess::exa_procedure, procedure->getId());
ExternalAccess temp(ExternalAccess::exa_procedure, proc()->getId());
FB_SIZE_T idx;
if (!csb->csb_external.find(temp, idx))
csb->csb_external.insert(idx, temp);

View File

@ -25,14 +25,9 @@
#define JRD_CMP_PROTO_H
#include "../jrd/req.h"
// req.h includes exe.h => Jrd::CompilerScratch and Jrd::CompilerScratch::csb_repeat.
// req.h includes exe.h => Jrd::CompilerScratch and Jrd::CompilerScratch::csb_repeat, Jrd::Subroutine
#include "../jrd/scl.h"
//namespace Jrd
//{
// class RelationSourceNode;
// ????????????????????????? }
StreamType* CMP_alloc_map(Jrd::thread_db*, Jrd::CompilerScratch*, StreamType stream);
Jrd::ValueExprNode* CMP_clone_node_opt(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::ValueExprNode*);
Jrd::BoolExprNode* CMP_clone_node_opt(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::BoolExprNode*);
@ -49,7 +44,7 @@ void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Jrd::MetaName
Jrd::SecurityClass::flags_t, ObjectType obj_type, const Jrd::MetaName&,
const Jrd::MetaName& = "");
void CMP_post_procedure_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_prc*);
void CMP_post_procedure_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::SubRoutine<Jrd::jrd_prc>);
Jrd::RecordSource* CMP_post_rse(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::RseNode*);
void CMP_release(Jrd::thread_db*, Jrd::Request*);

View File

@ -724,7 +724,7 @@ int CVT2_blob_compare(const dsc* arg1, const dsc* arg2, DecimalStatus decSt)
else
ttype1 = ttype_binary;
HazardPtr<TextType> obj1 = INTL_texttype_lookup(tdbb, ttype1);
TextType* obj1 = INTL_texttype_lookup(tdbb, ttype1);
ttype1 = obj1->getType();
// Is arg2 a blob?
@ -747,7 +747,7 @@ int CVT2_blob_compare(const dsc* arg1, const dsc* arg2, DecimalStatus decSt)
else
ttype2 = ttype_binary;
HazardPtr<TextType> obj2 = INTL_texttype_lookup(tdbb, ttype2);
TextType* obj2 = INTL_texttype_lookup(tdbb, ttype2);
ttype2 = obj2->getType();
if (ttype1 == ttype_binary || ttype2 == ttype_binary)

File diff suppressed because it is too large Load Diff

View File

@ -153,7 +153,7 @@ void DPM_backout( thread_db* tdbb, record_param* rpb)
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_backout (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
relation->getId(), rpb->rpb_number.getValue());
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT" back %"
@ -345,7 +345,7 @@ bool DPM_chain( thread_db* tdbb, record_param* org_rpb, record_param* new_rpb)
jrd_rel* relation = org_rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_chain (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d)\n",
relation->rel_id, org_rpb->rpb_number.getValue(),
relation->getId(), org_rpb->rpb_number.getValue(),
new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -560,21 +560,21 @@ void DPM_create_relation( thread_db* tdbb, jrd_rel* relation)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"DPM_create_relation (relation %d)\n", relation->rel_id);
"DPM_create_relation (relation %d)\n", relation->getId());
#endif
RelationPages* relPages = relation->getBasePages();
DPM_create_relation_pages(tdbb, relation, relPages);
RelationPages* relPages = relation->rel_perm->getBasePages();
DPM_create_relation_pages(tdbb, relation->rel_perm, relPages);
// Store page numbers in RDB$PAGES
DPM_pages(tdbb, relation->rel_id, pag_pointer, (ULONG) 0,
DPM_pages(tdbb, relation->getId(), pag_pointer, (ULONG) 0,
(*relPages->rel_pages)[0] /*window.win_page*/);
DPM_pages(tdbb, relation->rel_id, pag_root, (ULONG) 0,
DPM_pages(tdbb, relation->getId(), pag_root, (ULONG) 0,
relPages->rel_index_root /*root_window.win_page*/);
}
void DPM_create_relation_pages(thread_db* tdbb, jrd_rel* relation, RelationPages* relPages)
void DPM_create_relation_pages(thread_db* tdbb, RelationPermanent* relation, RelationPages* relPages)
{
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
@ -584,13 +584,13 @@ void DPM_create_relation_pages(thread_db* tdbb, jrd_rel* relation, RelationPages
WIN window(relPages->rel_pg_space_id, -1);
pointer_page* page = (pointer_page*) DPM_allocate(tdbb, &window);
page->ppg_header.pag_type = pag_pointer;
page->ppg_relation = relation->rel_id;
page->ppg_relation = relation->getId();
page->ppg_header.pag_flags = ppg_eof;
CCH_RELEASE(tdbb, &window);
// If this is relation 0 (RDB$PAGES), update the header
if (relation->rel_id == 0)
if (relation->getId() == 0)
{
WIN root_window(HEADER_PAGE_NUMBER);
header_page* header = (header_page*) CCH_FETCH(tdbb, &root_window, LCK_write, pag_header);
@ -604,7 +604,7 @@ void DPM_create_relation_pages(thread_db* tdbb, jrd_rel* relation, RelationPages
if (!relPages->rel_pages)
{
vcl* vector = vcl::newVector(*relation->rel_pool, 1);
vcl* vector = vcl::newVector(relation->getPool(), 1);
relPages->rel_pages = vector;
}
(*relPages->rel_pages)[0] = window.win_page.getPageNum();
@ -615,7 +615,7 @@ void DPM_create_relation_pages(thread_db* tdbb, jrd_rel* relation, RelationPages
WIN root_window(relPages->rel_pg_space_id, -1);
index_root_page* root = (index_root_page*) DPM_allocate(tdbb, &root_window);
root->irt_header.pag_type = pag_root;
root->irt_relation = relation->rel_id;
root->irt_relation = relation->getId();
//root->irt_count = 0;
CCH_RELEASE(tdbb, &root_window);
relPages->rel_index_root = root_window.win_page.getPageNum();
@ -640,7 +640,7 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"DPM_data_pages (relation %d)\n", relation->rel_id);
"DPM_data_pages (relation %d)\n", relation->getId());
#endif
RelationPages* relPages = relation->getPages(tdbb);
@ -945,7 +945,7 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
VIO_trace(DEBUG_WRITES_INFO,
"\tDPM_delete: page %" ULONGFORMAT
" is empty and about to be released from relation %d\n",
window->win_page.getPageNum(), rpb->rpb_relation->rel_id);
window->win_page.getPageNum(), rpb->rpb_relation->getId());
#endif
// Make sure that the pointer page is written after the data page.
@ -1002,7 +1002,7 @@ void DPM_delete( thread_db* tdbb, record_param* rpb, ULONG prior_page)
}
void DPM_delete_relation( thread_db* tdbb, jrd_rel* relation)
void DPM_delete_relation( thread_db* tdbb, RelationPermanent* relation)
{
/**************************************
*
@ -1025,7 +1025,7 @@ void DPM_delete_relation( thread_db* tdbb, jrd_rel* relation)
AutoRequest handle;
FOR(REQUEST_HANDLE handle) X IN RDB$PAGES WITH
X.RDB$RELATION_ID EQ relation->rel_id
X.RDB$RELATION_ID EQ relation->getId()
{
ERASE X;
}
@ -1047,12 +1047,12 @@ void DPM_delete_relation_pages(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation,
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"DPM_delete_relation_pages (relation %d, instance %" SQUADFORMAT")\n",
relation->rel_id, relPages->rel_instance_id);
relation->getId(), relPages->rel_instance_id);
#endif
// Delete all data and pointer pages
SortedArray<ULONG, InlineStorage<ULONG, 256> > pages(*relation->rel_pool);
SortedArray<ULONG, InlineStorage<ULONG, 256> > pages(relation->getPool());
for (ULONG sequence = 0; true; sequence++)
{
@ -1142,7 +1142,7 @@ bool DPM_fetch(thread_db* tdbb, record_param* rpb, USHORT lock)
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
relation->getId(), rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d\n", rpb->rpb_page, rpb->rpb_line);
@ -1205,7 +1205,7 @@ bool DPM_fetch_back(thread_db* tdbb, record_param* rpb, USHORT lock, SSHORT latc
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch_back (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
relation->getId(), rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -1270,7 +1270,7 @@ void DPM_fetch_fragment( thread_db* tdbb, record_param* rpb, USHORT lock)
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_fetch_fragment (rel_id %u, record_param %" QUADFORMAT"d, lock %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock);
relation->getId(), rpb->rpb_number.getValue(), lock);
VIO_trace(DEBUG_READS_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -1454,7 +1454,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type)
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_get (rel_id %u, record_param %" QUADFORMAT"d, lock type %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), lock_type);
relation->getId(), rpb->rpb_number.getValue(), lock_type);
#endif
WIN* window = &rpb->getWindow(tdbb);
@ -1483,7 +1483,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type)
const bool pageOk =
dpage->dpg_header.pag_type == pag_data &&
!(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) &&
dpage->dpg_relation == rpb->rpb_relation->rel_id &&
dpage->dpg_relation == rpb->rpb_relation->getId() &&
dpage->dpg_sequence == dpSequence &&
(dpage->dpg_count > 0);
@ -1562,7 +1562,7 @@ ULONG DPM_get_blob(thread_db* tdbb,
VIO_trace(DEBUG_READS,
"DPM_get_blob (rel_id %u, blob, record_number %" QUADFORMAT
"d, delete_flag %d, prior_page %" ULONGFORMAT")\n",
relation->rel_id, record_number.getValue(), (int)delete_flag, prior_page);
relation->getId(), record_number.getValue(), (int)delete_flag, prior_page);
#endif
// Find starting point
@ -1686,7 +1686,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, FindNextReco
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"DPM_next (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
relation->getId(), rpb->rpb_number.getValue());
#endif
WIN* window = &rpb->getWindow(tdbb);
@ -1747,7 +1747,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, FindNextReco
const bool pageOk =
dpage->dpg_header.pag_type == pag_data &&
!(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) &&
dpage->dpg_relation == rpb->rpb_relation->rel_id &&
dpage->dpg_relation == rpb->rpb_relation->getId() &&
dpage->dpg_sequence == dpSequence &&
(dpage->dpg_count > 0);
@ -2019,7 +2019,7 @@ void DPM_scan_pages( thread_db* tdbb)
// infinite recursion from this internal request when RDB$PAGES
// has been extended with another pointer page.
jrd_rel* relation = MetadataCache::findRelation(tdbb, 0);
RelationPermanent* relation = MetadataCache::lookupRelation(tdbb, 0u);
RelationPages* relPages = relation->getBasePages();
vcl** address = &relPages->rel_pages;
@ -2042,7 +2042,7 @@ void DPM_scan_pages( thread_db* tdbb)
FOR(REQUEST_HANDLE request) X IN RDB$PAGES
{
relation = MetadataCache::findRelation(tdbb, X.RDB$RELATION_ID);
relation = MetadataCache::lookupRelation(tdbb, X.RDB$RELATION_ID);
relPages = relation->getBasePages();
sequence = X.RDB$PAGE_SEQUENCE;
MemoryPool* pool = dbb->dbb_permanent;
@ -2054,7 +2054,7 @@ void DPM_scan_pages( thread_db* tdbb)
case pag_pointer:
address = &relPages->rel_pages;
pool = relation->rel_pool;
pool = &relation->getPool();
break;
case pag_transactions:
@ -2096,7 +2096,7 @@ void DPM_store( thread_db* tdbb, record_param* rpb, PageStack& stack, const Jrd:
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_store (rel_id %u, record_param %" QUADFORMAT"d, stack, type %d)\n",
relation->rel_id, rpb->rpb_number.getValue(), type);
relation->getId(), rpb->rpb_number.getValue(), type);
VIO_trace(DEBUG_WRITES_INFO,
" record to store %" ULONGFORMAT":%d transaction %" ULONGFORMAT
@ -2187,7 +2187,7 @@ RecordNumber DPM_store_blob(thread_db* tdbb, blb* blob, jrd_rel* relation, Recor
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"DPM_store_blob (rel_id %u, blob, record)\n",
relation->rel_id);
relation()->getId());
#endif
// Figure out length of blob on page. Remember that blob can either
@ -2261,7 +2261,7 @@ void DPM_rewrite_header( thread_db* tdbb, record_param* rpb)
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_rewrite_header (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
relation->getId(), rpb->rpb_number.getValue());
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d\n", rpb->rpb_page, rpb->rpb_line);
@ -2316,7 +2316,7 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"DPM_update (rel_id %u, record_param %" QUADFORMAT"d, stack, transaction %" ULONGFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
" record %" ULONGFORMAT":%d transaction %" ULONGFORMAT" back %"
@ -2694,7 +2694,7 @@ static void fragment(thread_db* tdbb,
VIO_trace(DEBUG_WRITES,
"fragment (rel_id %u, record_param %" QUADFORMAT
"d, available_space %d, dcc, length %d, transaction %" ULONGFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), available_space, length,
relation->getId(), rpb->rpb_number.getValue(), available_space, length,
transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -2869,7 +2869,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" extend_relation (relation %d, instance %" SQUADFORMAT", window)\n",
relation->rel_id, relPages->rel_instance_id);
relation->getId(), relPages->rel_instance_id);
#endif
// Search pointer pages for an empty slot.
@ -2915,20 +2915,20 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
pointer_page* new_ppage = (pointer_page*) DPM_allocate(tdbb, &new_pp_window);
new_ppage->ppg_header.pag_type = pag_pointer;
new_ppage->ppg_header.pag_flags |= ppg_eof;
new_ppage->ppg_relation = relation->rel_id;
new_ppage->ppg_relation = relation->getId();
new_ppage->ppg_sequence = ++pp_sequence;
slot = 0;
CCH_must_write(tdbb, &new_pp_window);
CCH_RELEASE(tdbb, &new_pp_window);
vcl* vector = relPages->rel_pages =
vcl::newVector(*relation->rel_pool, relPages->rel_pages, pp_sequence + 1);
vcl::newVector(relation->getPool(), relPages->rel_pages, pp_sequence + 1);
(*vector)[pp_sequence] = new_pp_window.win_page.getPageNum();
// hvlad: temporary tables don't save their pointer pages in RDB$PAGES
if (relation->rel_id && (relPages->rel_instance_id == 0))
if (relation->getId() && (relPages->rel_instance_id == 0))
{
DPM_pages(tdbb, relation->rel_id, pag_pointer,
DPM_pages(tdbb, relation->getId(), pag_pointer,
pp_sequence, new_pp_window.win_page.getPageNum());
}
relPages->rel_slot_space = pp_sequence;
@ -2965,7 +2965,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
const PageNumber firstPage = window->win_page;
dpage->dpg_sequence = pp_sequence * dbb->dbb_dp_per_pp + slot;
dpage->dpg_relation = relation->rel_id;
dpage->dpg_relation = relation->getId();
dpage->dpg_header.pag_type = pag_data;
if (type != DPM_primary) {
dpage->dpg_header.pag_flags |= dpg_secondary;
@ -2980,7 +2980,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
dpage = (data_page*) CCH_fake(tdbb, window, 1);
dpage->dpg_sequence = pp_sequence * dbb->dbb_dp_per_pp + slot + i;
dpage->dpg_relation = relation->rel_id;
dpage->dpg_relation = relation->getId();
dpage->dpg_header.pag_type = pag_data;
CCH_RELEASE_TAIL(tdbb, window);
@ -3026,7 +3026,7 @@ static void extend_relation(thread_db* tdbb, jrd_rel* relation, WIN* window, con
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" extended_relation (relation %d, window_page %" ULONGFORMAT")\n",
relation->rel_id, window->win_page.getPageNum());
relation->getId(), window->win_page.getPageNum());
#endif
}
@ -3197,7 +3197,7 @@ static bool get_header(WIN* window, USHORT line, record_param* rpb)
rpb->rpb_transaction_nr = Ods::getTraNum(header);
rpb->rpb_format_number = header->rhdf_format;
if (rpb->rpb_relation->rel_id == 0 /*i.e.RDB$PAGES*/ && rpb->rpb_transaction_nr != 0)
if (rpb->rpb_relation->getId() == 0 /*i.e.RDB$PAGES*/ && rpb->rpb_transaction_nr != 0)
{
// RDB$PAGES relation should be modified only by system transaction
ERR_post(Arg::Gds(isc_wrong_page));
@ -3261,14 +3261,14 @@ static pointer_page* get_pointer_page(thread_db* tdbb,
// hvlad: temporary tables don't save their pointer pages in RDB$PAGES
if (relPages->rel_instance_id == 0)
DPM_pages(tdbb, relation->rel_id, pag_pointer, vector->count(), next_ppg);
DPM_pages(tdbb, relation->getId(), pag_pointer, vector->count(), next_ppg);
}
}
window->win_page = (*vector)[sequence];
pointer_page* page = (pointer_page*) CCH_FETCH(tdbb, window, lock, pag_pointer);
if (page->ppg_relation != relation->rel_id || page->ppg_sequence != sequence)
if (page->ppg_relation != relation->getId() || page->ppg_sequence != sequence)
CORRUPT(259); // msg 259 bad pointer page
return page;
@ -3344,7 +3344,7 @@ static rhd* locate_space(thread_db* tdbb,
const bool pageOk =
dpage->dpg_header.pag_type == pag_data &&
!(dpage->dpg_header.pag_flags & wrongFlags) &&
dpage->dpg_relation == rpb->rpb_relation->rel_id &&
dpage->dpg_relation == rpb->rpb_relation->getId() &&
//dpage->dpg_sequence == dpSequence &&
(dpage->dpg_count > 0);
@ -3527,7 +3527,7 @@ static rhd* locate_space(thread_db* tdbb,
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO,
" extended relation %d with page %" ULONGFORMAT" to get %d bytes\n",
relation->rel_id, window->win_page.getPageNum(), size);
relation->getId(), window->win_page.getPageNum(), size);
#endif
return (rhd*) space;
@ -3554,7 +3554,7 @@ static void mark_full(thread_db* tdbb, record_param* rpb)
jrd_rel* relation = rpb->rpb_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"mark_full (rel_id %u)\n", relation->rel_id);
"mark_full (rel_id %u)\n", relation->getId());
#endif
// We need to access the pointer page for write. To avoid deadlocks,
@ -3713,7 +3713,7 @@ static void store_big_record(thread_db* tdbb,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE_ALL,
"store_big_record (rel_id %u, record %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue());
relation->getId(), rpb->rpb_number.getValue());
#endif
// Start compression from the end.
@ -3739,7 +3739,7 @@ static void store_big_record(thread_db* tdbb,
data_page* page = (data_page*) DPM_allocate(tdbb, &rpb->getWindow(tdbb));
page->dpg_header.pag_type = pag_data;
page->dpg_header.pag_flags = dpg_orphan | dpg_full;
page->dpg_relation = rpb->rpb_relation->rel_id;
page->dpg_relation = rpb->rpb_relation->getId();
page->dpg_count = 1;
const auto inLength = dcc.truncateTail(max_data);

View File

@ -27,6 +27,7 @@
#include "../jrd/RecordNumber.h"
#include "../jrd/sbm.h"
#include "../jrd/vio_proto.h"
#include "../jrd/Resource.h"
// fwd. decl.
namespace Jrd
@ -62,13 +63,13 @@ bool DPM_chain(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*);
void DPM_create_relation(Jrd::thread_db*, Jrd::jrd_rel*);
ULONG DPM_data_pages(Jrd::thread_db*, Jrd::jrd_rel*);
void DPM_delete(Jrd::thread_db*, Jrd::record_param*, ULONG);
void DPM_delete_relation(Jrd::thread_db*, Jrd::jrd_rel*);
void DPM_delete_relation(Jrd::thread_db*, Jrd::RelationPermanent*);
bool DPM_fetch(Jrd::thread_db*, Jrd::record_param*, USHORT);
bool DPM_fetch_back(Jrd::thread_db*, Jrd::record_param*, USHORT, SSHORT);
void DPM_fetch_fragment(Jrd::thread_db*, Jrd::record_param*, USHORT);
SINT64 DPM_gen_id(Jrd::thread_db*, SLONG, bool, SINT64);
bool DPM_get(Jrd::thread_db*, Jrd::record_param*, SSHORT);
ULONG DPM_get_blob(Jrd::thread_db*, Jrd::blb*, RecordNumber, bool, ULONG);
ULONG DPM_get_blob(Jrd::thread_db*, Jrd::blb*, Jrd::jrd_rel*, RecordNumber, bool, ULONG);
bool DPM_next(Jrd::thread_db*, Jrd::record_param*, USHORT, Jrd::FindNextRecordScope);
void DPM_pages(Jrd::thread_db*, SSHORT, int, ULONG, ULONG);
#ifdef SUPERSERVER_V2
@ -80,7 +81,7 @@ RecordNumber DPM_store_blob(Jrd::thread_db*, Jrd::blb*, Jrd::jrd_rel*, Jrd::Reco
void DPM_rewrite_header(Jrd::thread_db*, Jrd::record_param*);
void DPM_update(Jrd::thread_db*, Jrd::record_param*, Jrd::PageStack*, const Jrd::jrd_tra*);
void DPM_create_relation_pages(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::RelationPages*);
void DPM_delete_relation_pages(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::RelationPages*);
void DPM_create_relation_pages(Jrd::thread_db*, Jrd::RelationPermanent*, Jrd::RelationPages*);
void DPM_delete_relation_pages(Jrd::thread_db*, Jrd::RelationPermanent*, Jrd::RelationPages*);
#endif // JRD_DPM_PROTO_H

View File

@ -324,7 +324,7 @@ void EVL_dbkey_bounds(thread_db* tdbb, const Array<DbKeyRangeNode*>& ranges,
Aligner<RecordNumber::Packed> alignedNumber(ptr, length);
const auto dbkey = (const RecordNumber::Packed*) alignedNumber;
if (dbkey->bid_relation_id == relation->rel_id)
if (dbkey->bid_relation_id == relation->getId())
{
RecordNumber recno;
recno.bid_decode(dbkey);
@ -357,7 +357,7 @@ void EVL_dbkey_bounds(thread_db* tdbb, const Array<DbKeyRangeNode*>& ranges,
Aligner<RecordNumber::Packed> alignedNumber(ptr, length);
const auto dbkey = (const RecordNumber::Packed*) alignedNumber;
if (dbkey->bid_relation_id == relation->rel_id)
if (dbkey->bid_relation_id == relation->getId())
{
RecordNumber recno;
recno.bid_decode(dbkey);
@ -429,7 +429,7 @@ bool EVL_field(jrd_rel* relation, Record* record, USHORT id, dsc* desc)
break;
}
format = MET_format(tdbb, relation, format->fmt_version + 1);
format = MET_format(tdbb, relation->rel_perm, format->fmt_version + 1);
fb_assert(format);
}

View File

@ -530,7 +530,7 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, TriggerActio
return;
}
TrigVectorPtr* triggers = attachment->att_database->dbb_mdc->getTriggers(type | TRIGGER_TYPE_DB);
const Triggers* triggers = attachment->att_database->dbb_mdc->getTriggers(type | TRIGGER_TYPE_DB);
if (triggers && *triggers)
{
jrd_tra* old_transaction = tdbb->getTransaction();
@ -538,7 +538,7 @@ void EXE_execute_db_triggers(thread_db* tdbb, jrd_tra* transaction, TriggerActio
try
{
EXE_execute_triggers(tdbb, triggers, NULL, NULL, trigger_action, StmtNode::ALL_TRIGS);
EXE_execute_triggers(tdbb, *triggers, NULL, NULL, trigger_action, StmtNode::ALL_TRIGS);
tdbb->setTransaction(old_transaction);
}
catch (const Exception&)
@ -556,30 +556,28 @@ void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTri
Jrd::Database* const dbb = tdbb->getDatabase();
// Our caller verifies (ATT_no_db_triggers) if DDL triggers should not run.
TrigVectorPtr* cachedTriggers = dbb->dbb_mdc->getTriggers(TRIGGER_TYPE_DDL);
const Triggers* cachedTriggers = dbb->dbb_mdc->getTriggers(TRIGGER_TYPE_DDL);
if (cachedTriggers && *cachedTriggers)
{
TrigVector triggers;
TrigVector* triggersPtr = &triggers;
unsigned n = 0;
Triggers triggers;
for (auto t : cachedTriggers->load()->snapshot())
for (auto t : *cachedTriggers)
{
const bool preTrigger = ((t->type & 0x1) == 0);
if ((t->type & (1LL << action)) && (preTriggers == preTrigger))
triggers.store(tdbb, n++, t);
triggers.addTrigger(tdbb, t);
}
if (triggers.hasData())
if (triggers)
{
jrd_tra* const oldTransaction = tdbb->getTransaction();
tdbb->setTransaction(transaction);
try
{
EXE_execute_triggers(tdbb, &triggersPtr, NULL, NULL, TRIGGER_DDL,
EXE_execute_triggers(tdbb, triggers, NULL, NULL, TRIGGER_DDL,
preTriggers ? StmtNode::PRE_TRIG : StmtNode::POST_TRIG);
tdbb->setTransaction(oldTransaction);
@ -887,7 +885,7 @@ void EXE_start(thread_db* tdbb, Request* request, jrd_tra* transaction)
provide transaction stability by preventing a relation from being
dropped after it has been referenced from an active transaction. */
TRA_post_resources(tdbb, transaction, statement->resources);
transaction->postResources(tdbb, statement->getResources());
TRA_attach_request(transaction, request);
request->req_flags &= req_restart_ready;
@ -1117,7 +1115,7 @@ static void execute_looper(thread_db* tdbb,
void EXE_execute_triggers(thread_db* tdbb,
TrigVectorPtr* triggers,
const Triggers& triggers,
record_param* old_rpb,
record_param* new_rpb,
TriggerAction trigger_action, StmtNode::WhichTrigger which_trig)
@ -1133,15 +1131,11 @@ void EXE_execute_triggers(thread_db* tdbb,
* if any blow up.
*
**************************************/
if (!(triggers && *triggers))
return;
SET_TDBB(tdbb);
Request* const request = tdbb->getRequest();
jrd_tra* const transaction = request ? request->req_transaction : tdbb->getTransaction();
TrigVectorPtr vector(triggers->load());
Record* const old_rec = old_rpb ? old_rpb->rpb_record : NULL;
Record* const new_rec = new_rpb ? new_rpb->rpb_record : NULL;
@ -1171,10 +1165,8 @@ void EXE_execute_triggers(thread_db* tdbb,
try
{
for (auto ptr : vector.load()->snapshot())
for (auto* ptr : triggers)
{
ptr->compile(tdbb);
trigger = ptr->statement->findRequest(tdbb);
if (!is_db_trigger)
@ -1252,15 +1244,9 @@ void EXE_execute_triggers(thread_db* tdbb,
trigger = NULL;
}
if (vector != *triggers)
MET_release_triggers(tdbb, &vector, true);
}
catch (const Exception& ex)
{
if (vector != *triggers)
MET_release_triggers(tdbb, &vector, true);
if (trigger)
{
EXE_unwind(tdbb, trigger);
@ -1712,392 +1698,3 @@ void AutoRequest::release()
}
}
void ResourceList::setResetPointersHazard(thread_db* tdbb, bool set)
{
if (hazardFlag != set)
{
// (un-)register hazard pointers
for (auto r : list)
{
void* hazardPointer = nullptr;
switch (r.rsc_type)
{
case Resource::rsc_relation:
hazardPointer = r.rsc_rel;
break;
case Resource::rsc_index:
break;
case Resource::rsc_procedure:
case Resource::rsc_function:
hazardPointer = r.rsc_routine;
break;
case Resource::rsc_collation:
hazardPointer = r.rsc_coll;
break;
}
if (hazardPointer)
{
if (set)
hazardDelayed->add(hazardPointer, FB_FUNCTION);
else
hazardDelayed->remove(hazardPointer, FB_FUNCTION);
}
}
hazardFlag = set;
}
}
void ResourceList::transferList(thread_db* tdbb, const InternalResourceList& from,
Resource::State resetState, ResourceTypes rt, NewResources* nr, ResourceList* hazardList)
{
// Copy needed resources
FB_SIZE_T pos = 0;
for (auto src : from)
{
if (src.rsc_state == Resource::State::Registered) // registered but never posted
continue;
if (!rt.test(src.rsc_type)) // skip some types of resources
continue;
while (pos < list.getCount() && src > list[pos])
++pos;
list.insert(pos, src);
nr->push(pos);
if (resetState != Resource::State::Locked) // The strongest state
list[pos].rsc_state = resetState;
++pos; // minor performance optimization
}
// Increase use counters
NewResources toLock;
{ // scope
//MutexEnsureUnlock g(tdbb->getDatabase()->dbb_mdc->mdc_use_mutex, FB_FUNCTION);
MutexLockGuard g(tdbb->getDatabase()->dbb_mdc->mdc_use_mutex, FB_FUNCTION);
//bool useMutexLocked = false;
for (auto n : *nr)
{
Resource& r = list[n];
if (r.rsc_state != Resource::State::Posted) // use count was already increased
continue;
/*
// First take care about locking
switch (r.rsc_type)
{
case Resource::rsc_procedure:
case Resource::rsc_function:
if (!useMutexLocked)
{
g.enter();
useMutexLocked = true;
}
break;
default:
if (useMutexLocked)
{
g.leave();
useMutexLocked = false;
}
break;
}
// Next increment counter
*/ switch (r.rsc_type)
{
case Resource::rsc_relation:
{
ExistenceLock* lock = r.rsc_rel->rel_existence_lock;
r.rsc_state = lock ? lock->inc(tdbb) : Resource::State::Locked;
break;
}
case Resource::rsc_index:
// Relation locks MUST be taken before index locks - skip it here.
break;
case Resource::rsc_procedure:
case Resource::rsc_function:
{
ExistenceLock* lock = r.rsc_routine->existenceLock;
r.rsc_state = lock ? lock->inc(tdbb) : Resource::State::Locked;
#ifdef DEBUG_PROCS
string buffer;
buffer.printf(
"Called from Statement::makeRequest:\n\t Incrementing use count of %s\n",
routine->getName()->toString().c_str());
JRD_print_procedure_info(tdbb, buffer.c_str());
#endif
break;
}
case Resource::rsc_collation:
{
Collation* coll = r.rsc_coll;
coll->incUseCount(tdbb);
break;
}
default:
BUGCHECK(219); // msg 219 request of unknown resource
}
if (r.rsc_state != Resource::State::Locked)
toLock.push(n);
}
}
if (hazardList)
hazardList->setResetPointersHazard(tdbb, false);
// Now lock not yet locked objects
for (auto n : toLock)
{
Resource& r = list[n];
if (r.rsc_state != Resource::State::Counted) // use count was already increased
continue;
ExistenceLock* lock = nullptr;
switch (r.rsc_type)
{
case Resource::rsc_relation:
lock = r.rsc_rel->rel_existence_lock;
break;
case Resource::rsc_index:
{
HazardPtr<IndexLock> index = r.rsc_rel->getIndexLock(tdbb, r.rsc_id);
r.rsc_state = index ? index->idl_lock.inc(tdbb) : Resource::State::Locked;
if (index && r.rsc_state != Resource::State::Locked)
lock = &index->idl_lock;
}
break;
case Resource::rsc_procedure:
case Resource::rsc_function:
lock = r.rsc_routine->existenceLock;
break;
case Resource::rsc_collation:
{
Collation* coll = r.rsc_coll;
break;
}
}
if (lock)
lock->enter245(tdbb);
r.rsc_state = Resource::State::Locked;
}
}
void ResourceList::raiseNotRegistered(const Resource& r, Resource::rsc_s type, const char* name)
{
if (r.rsc_rel && r.rsc_rel->isSystem())
return;
// Resource type (r.type) and actual type may differ when working with index
const char* typeName = nullptr;
switch (type)
{
case Resource::rsc_relation:
typeName = "Relation";
break;
case Resource::rsc_index:
typeName = "Index";
break;
case Resource::rsc_procedure:
typeName = "Procedure";
break;
case Resource::rsc_function:
typeName = "Function";
break;
case Resource::rsc_collation:
typeName = "Collation";
break;
}
fb_assert(typeName);
string msg;
msg.printf("%s %s was not registered for use by request or transaction", typeName, name);
ERR_post(Arg::Gds(isc_random) << msg);
}
void ResourceList::transferResources(thread_db* tdbb, ResourceList& from,
ResourceTypes rt, NewResources& nr)
{
transferList(tdbb, from.list, Resource::State::Posted, rt, &nr, nullptr);
}
void ResourceList::transferResources(thread_db* tdbb, ResourceList& from)
{
NewResources work;
transferList(tdbb, from.list, Resource::State::Locked, ResourceTypes().setAll(), &work, &from);
}
void ResourceList::releaseResources(thread_db* tdbb, jrd_tra* transaction)
{
// 0. Get ready to run drom dtor()
if (!list.hasData())
return;
if (!tdbb)
tdbb = JRD_get_thread_data();
// 1. Need to take hazard locks on all involved objects
setResetPointersHazard(tdbb, true);
// 2. First of all release indices - they do not need refcnt mutex locked
for (auto r : getObjects(Resource::rsc_index))
{
HazardPtr<IndexLock> index = r->rsc_rel->getIndexLock(tdbb, r->rsc_id);
if (index)
{
if (r->rsc_state == Resource::State::Locked)
r->rsc_state = index->idl_lock.dec(tdbb);
else if (r->rsc_state == Resource::State::Counted)
{
r->rsc_state = Resource::State::Posted;
index->idl_lock.dec(tdbb);
}
if (r->rsc_state == Resource::State::Unlocking)
{
index->idl_lock.leave245(tdbb);
r->rsc_state = Resource::State::Posted;
}
}
else
r->rsc_state = Resource::State::Posted;
}
// 3. Decrement lock count of all objects - refcnt mutex to be locked
HalfStaticArray<Resource*, 128> toUnlock;
{ // scope
MutexLockGuard g(tdbb->getDatabase()->dbb_mdc->mdc_use_mutex, FB_FUNCTION);
for (auto r : list)
{
if (r.rsc_state == Resource::State::Extra)
{
fb_assert(r.rsc_type == Resource::rsc_relation);
if (r.rsc_rel && r.rsc_rel->rel_file)
{
if (!transaction)
transaction = tdbb->getTransaction();
fb_assert(transaction);
if (transaction)
EXT_tra_detach(r.rsc_rel->rel_file, transaction);
}
r.rsc_state = Resource::State::Locked;
}
if (r.rsc_state == Resource::State::Posted ||
r.rsc_state == Resource::State::Registered ||
r.rsc_state == Resource::State::Unlocking) // use count is not increased
{
continue;
}
switch (r.rsc_type)
{
case Resource::rsc_relation:
{
ExistenceLock* lock = r.rsc_rel->rel_existence_lock;
r.rsc_state = lock ? lock->dec(tdbb) : Resource::State::Posted;
break;
}
case Resource::rsc_index:
break;
case Resource::rsc_procedure:
case Resource::rsc_function:
{
ExistenceLock* lock = r.rsc_routine->existenceLock;
r.rsc_state = lock ? lock->dec(tdbb) : Resource::State::Posted;
break;
}
case Resource::rsc_collation:
{
Collation* coll = r.rsc_coll;
coll->decUseCount(tdbb);
break;
}
default:
BUGCHECK(219); // msg 219 request of unknown resource
}
if (r.rsc_state == Resource::State::Unlocking)
toUnlock.push(&r);
}
}
// 4. Release not needed any more locks
for (auto r : toUnlock)
{
fb_assert(r->rsc_state == Resource::State::Unlocking);
ExistenceLock* lock = nullptr;
switch (r->rsc_type)
{
case Resource::rsc_relation:
lock = r->rsc_rel->rel_existence_lock;
break;
case Resource::rsc_index:
fb_assert(false);
break;
case Resource::rsc_procedure:
case Resource::rsc_function:
lock = r->rsc_routine->existenceLock;
break;
case Resource::rsc_collation:
{
Collation* coll = r->rsc_coll;
break;
}
}
if (lock)
lock->leave245(tdbb);
r->rsc_state = Resource::State::Posted;
}
// 5. Finally time to release hazard locks on objects and cleanup
setResetPointersHazard(tdbb, false);
list.clear();
}
void ResourceList::postIndex(thread_db* tdbb, jrd_rel* relation, USHORT idxId)
{
abort();
// resources.checkResource(Resource::rsc_relation, relation);
// resources.postResource(Resource::rsc_index, relation, idx->idx_id);
}

View File

@ -46,6 +46,7 @@
#include "../common/dsc.h"
#include "../jrd/err_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/scl.h"
#include "../jrd/sbm.h"
#include "../jrd/sort.h"
@ -168,96 +169,6 @@ struct impure_agg_sort
};
template <class OBJ> class CacheElement;
class Resources
{
public:
template <class OBJ>
class VersionedPtr
{
public:
CacheElement<OBJ>* ptr;
FB_SIZE_T versionedObject;
};
template <class OBJ>
class RscArray : public Firebird::Array<VersionedPtr<OBJ>>
{
public:
RscArray(MemoryPool& p)
: Firebird::Array<VersionedPtr<OBJ>>(p)
{ }
FB_SIZE_T registerResource(CacheElement<OBJ>* res)
{
FB_SIZE_T pos;
if (this->find([res](const VersionedPtr<OBJ>& elem) {
const void* p1 = elem.ptr;
const void* p2 = res;
return p1 < p2 ? -1 : p1 == p2 ? 0 : 1;
}, pos))
{
return pos;
}
VersionedPtr<OBJ> newPtr(res);
return this->append(newPtr);
}
};
public:
template <class OBJ> const RscArray<OBJ>& objects() const;
Resources(MemoryPool& p)
: charSets(p), relations(p), procedures(p), functions(p), triggers(p)
{ }
RscArray<CharSetContainer> charSets;
RscArray<jrd_rel> relations;
RscArray<jrd_prc> procedures;
RscArray<Function> functions;
RscArray<Trigger> triggers;
};
// specialization
template <> const Resources::RscArray<jrd_rel>& Resources::objects() const { return relations; }
template <class OBJ>
class CachedResource
{
public:
CachedResource(FB_SIZE_T offset)
: compileOffset(offset)
{ }
CachedResource();
OBJ* get(thread_db* tdbb, const Resources* compileTime) const
{
auto array = compileTime->objects<OBJ>();
return array[compileOffset]->ptr->getObject(tdbb);
}
bool isSet() const;
/*
operator OBJ*() const
{
return getPtr();
}
OBJ* operator->() const
{
return getPtr();
}
*/
private:
FB_SIZE_T compileOffset;
};
// Access items
// In case we start to use MetaName with required pool parameter,
// access item to be reworked!
@ -481,34 +392,90 @@ typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<MetaNamePair, FieldIn
MapFieldInfo;
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Right<Item, ItemInfo> > > MapItemInfo;
template <class R>
class SubRoutine
{
public:
SubRoutine()
: routine(), subroutine(nullptr)
{ }
SubRoutine(const CachedResource<R, RoutinePermanent>& r)
: routine(r), subroutine(nullptr)
{ }
SubRoutine(R* r)
: routine(), subroutine(r)
{ }
SubRoutine& operator=(const CachedResource<R, RoutinePermanent>& r)
{
routine = r;
subroutine = nullptr;
return *this;
}
SubRoutine& operator=(R* r)
{
routine.clear();
subroutine = r;
return *this;
}
R* operator()(thread_db* tdbb) const
{
return isSubRoutine() ? subroutine : routine(tdbb);
}
RoutinePermanent* operator()() const
{
return isSubRoutine() ? subroutine->permanent : routine();
}
bool isSubRoutine() const
{
return subroutine != nullptr;
}
operator bool() const
{
fb_assert((routine.isSet() ? 1 : 0) + (subroutine ? 1 : 0) < 2);
return routine.isSet() || subroutine;
}
private:
CachedResource<R, RoutinePermanent> routine;
R* subroutine;
};
// Compile scratch block
struct Dependency
{
explicit Dependency(int aObjType)
{
memset(this, 0, sizeof(*this));
objType = aObjType;
}
int objType;
union
{
jrd_rel* relation;
const Function* function;
const jrd_prc* procedure;
const MetaName* name;
SLONG number;
};
const MetaName* subName;
SLONG subNumber;
};
class CompilerScratch : public pool_alloc<type_csb>
{
public:
struct Dependency
{
explicit Dependency(int aObjType)
{
memset(this, 0, sizeof(*this));
objType = aObjType;
}
int objType;
union
{
jrd_rel* relation;
const Function* function;
const jrd_prc* procedure;
const MetaName* name;
SLONG number;
};
const MetaName* subName;
SLONG subNumber;
};
explicit CompilerScratch(MemoryPool& p, CompilerScratch* aMainCsb = NULL)
: /*csb_node(0),
csb_variables(0),
@ -630,9 +597,9 @@ public:
MetaName csb_domain_validation; // Parsing domain constraint in PSQL
// used in cmp.cpp/pass1
CachedResource<jrd_rel> csb_view;
Rsc::Rel csb_view;
StreamType csb_view_stream;
CachedResource<jrd_rel> csb_parent_relation;
Rsc::Rel csb_parent_relation;
unsigned blrVersion;
USHORT csb_remap_variable;
bool csb_validate_expr;
@ -666,10 +633,10 @@ public:
StreamType csb_view_stream; // stream number for view relation, below
USHORT csb_flags;
CachedResource<jrd_rel> csb_relation;
Rsc::Rel csb_relation;
Firebird::string* csb_alias; // SQL alias name for this instance of relation
CachedResource<jrd_prc> csb_procedure;
CachedResource<jrd_rel> csb_view; // parent view
SubRoutine<jrd_prc> csb_procedure;
Rsc::Rel csb_view; // parent view
IndexDescList* csb_idx; // Packed description of indices
MessageNode* csb_message; // Msg for send/receive
@ -692,10 +659,9 @@ inline CompilerScratch::csb_repeat::csb_repeat()
: csb_stream(0),
csb_view_stream(0),
csb_flags(0),
csb_relation(0),
csb_relation(),
csb_alias(0),
csb_procedure(0),
csb_view(0),
csb_view(),
csb_idx(0),
csb_message(0),
csb_format(0),

View File

@ -52,7 +52,7 @@ bool EXE_get_stack_trace(const Jrd::Request* request, Firebird::string& sTrace);
const Jrd::StmtNode* EXE_looper(Jrd::thread_db* tdbb, Jrd::Request* request,
const Jrd::StmtNode* in_node);
void EXE_execute_triggers(Jrd::thread_db*, Jrd::TrigVectorPtr*, Jrd::record_param*, Jrd::record_param*,
void EXE_execute_triggers(Jrd::thread_db*, const Jrd::Triggers&, Jrd::record_param*, Jrd::record_param*,
enum TriggerAction, Jrd::StmtNode::WhichTrigger);
void EXE_receive(Jrd::thread_db*, Jrd::Request*, USHORT, ULONG, void*, bool = false);

View File

@ -38,17 +38,18 @@
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include "../jrd/ext_proto.h"
#include "../jrd/jrd.h"
#include "../jrd/req.h"
#include "../jrd/val.h"
#include "../jrd/exe.h"
#include "../jrd/ext.h"
#include "../jrd/tra.h"
#include "../dsql/ExprNodes.h"
#include "iberror.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/ext_proto.h"
#include "../yvalve/gds_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/mov_proto.h"
@ -118,47 +119,47 @@ namespace {
#ifdef WIN_NT
static const char* const FOPEN_TYPE = "a+b";
static const char* const FOPEN_READ_ONLY = "rb";
#else
static const char* const FOPEN_TYPE = "a+";
static const char* const FOPEN_READ_ONLY = "r";
#endif
static const char* const FOPEN_READ_ONLY = "rb";
FILE* ext_fopen(Database* dbb, ExternalFile* ext_file)
{
const char* file_name = ext_file->ext_filename;
ExternalFileDirectoryList::create(dbb);
if (!dbb->dbb_external_file_directory_list->isPathInList(file_name))
{
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("external file") <<
Arg::Str(file_name));
}
// If the database is updateable, then try opening the external files in
// RW mode. If the DB is ReadOnly, then open the external files only in
// ReadOnly mode, thus being consistent.
if (!dbb->readOnly())
ext_file->ext_ifi = os_utils::fopen(file_name, FOPEN_TYPE);
if (!ext_file->ext_ifi)
{
// could not open the file as read write attempt as read only
if (!(ext_file->ext_ifi = os_utils::fopen(file_name, FOPEN_READ_ONLY)))
{
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fopen") << Arg::Str(file_name) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
}
else {
ext_file->ext_flags |= EXT_readonly;
}
}
return ext_file->ext_ifi;
}
} // namespace
void ExternalFile::open(Database* dbb)
{
fb_assert(ext_sync.locked());
double EXT_cardinality(thread_db* tdbb, jrd_rel* relation)
ExternalFileDirectoryList::create(dbb);
if (!dbb->dbb_external_file_directory_list->isPathInList(ext_filename))
{
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("external file") <<
Arg::Str(ext_filename));
}
// If the database is updateable then try opening the external files in RW mode.
ext_flags = 0;
if (!dbb->readOnly())
ext_ifi = os_utils::fopen(ext_filename, FOPEN_TYPE);
// If the DB is ReadOnly or RW access failed then open the external files only in ReadOnly mode.
if (!ext_ifi)
{
if (!(ext_ifi = os_utils::fopen(ext_filename, FOPEN_READ_ONLY)))
{
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fopen") << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
}
else {
ext_flags |= EXT_readonly;
}
}
}
double ExternalFile::getCardinality(thread_db* tdbb, jrd_rel* relation) noexcept
{
/**************************************
*
@ -170,35 +171,24 @@ double EXT_cardinality(thread_db* tdbb, jrd_rel* relation)
* Return cardinality for the external file.
*
**************************************/
ExternalFile* const file = relation->rel_file;
fb_assert(file);
try
{
bool must_close = false;
if (!file->ext_ifi)
{
ext_fopen(tdbb->getDatabase(), file);
must_close = true;
}
FB_UINT64 file_size = 0;
// no need locking mutex here
traAttach(tdbb);
{ // scope
Cleanup clean([this]() { traDetach(); });
#ifdef WIN_NT
struct __stat64 statistics;
if (!_fstat64(_fileno(file->ext_ifi), &statistics))
struct __stat64 statistics;
if (!_fstat64(_fileno(ext_ifi), &statistics))
#else
struct STAT statistics;
if (!os_utils::fstat(fileno(file->ext_ifi), &statistics))
struct STAT statistics;
if (!os_utils::fstat(fileno(ext_ifi), &statistics))
#endif
{
file_size = statistics.st_size;
}
if (must_close)
{
fclose(file->ext_ifi);
file->ext_ifi = NULL;
{
file_size = statistics.st_size;
}
}
const Format* const format = MET_current(tdbb, relation);
@ -217,7 +207,7 @@ double EXT_cardinality(thread_db* tdbb, jrd_rel* relation)
}
void EXT_erase(record_param*, jrd_tra*)
void ExternalFile::erase(record_param*, jrd_tra*)
{
/**************************************
*
@ -234,8 +224,7 @@ void EXT_erase(record_param*, jrd_tra*)
}
// Third param is unused.
ExternalFile* EXT_file(jrd_rel* relation, const TEXT* file_name) //, bid* description)
void RelationPermanent::extFile(thread_db* tdbb, const TEXT* file_name)
{
/**************************************
*
@ -250,11 +239,7 @@ ExternalFile* EXT_file(jrd_rel* relation, const TEXT* file_name) //, bid* descri
Database* dbb = GET_DBB();
CHECK_DBB(dbb);
// if we already have a external file associated with this relation just
// return the file structure
if (relation->rel_file) {
EXT_fini(relation.getPointer(), false);
}
fb_assert(!rel_file);
#ifdef WIN_NT
// Default number of file handles stdio.h on Windows is 512, use this
@ -304,48 +289,11 @@ ExternalFile* EXT_file(jrd_rel* relation, const TEXT* file_name) //, bid* descri
paths.clear();
ExternalFile* file = FB_NEW_RPT(*relation->rel_pool, (strlen(file_name) + 1)) ExternalFile();
relation->rel_file = file;
strcpy(file->ext_filename, file_name);
file->ext_flags = 0;
file->ext_ifi = NULL;
return file;
rel_file = ExternalFile::create(getPool(), file_name);
}
void EXT_fini(jrd_rel* relation, bool close_only)
{
/**************************************
*
* E X T _ f i n i
*
**************************************
*
* Functional description
* Close the file associated with a relation.
*
**************************************/
if (relation->rel_file)
{
ExternalFile* file = relation->rel_file;
if (file->ext_ifi)
{
fclose(file->ext_ifi);
file->ext_ifi = NULL;
}
// before zeroing out the rel_file we need to deallocate the memory
if (!close_only)
{
delete file;
relation->rel_file = NULL;
}
}
}
bool EXT_get(thread_db* tdbb, record_param* rpb, FB_UINT64& position)
bool ExternalFile::get(thread_db* tdbb, record_param* rpb, FB_UINT64& position)
{
/**************************************
*
@ -358,8 +306,7 @@ bool EXT_get(thread_db* tdbb, record_param* rpb, FB_UINT64& position)
*
**************************************/
jrd_rel* const relation = rpb->rpb_relation;
ExternalFile* const file = relation->rel_file;
fb_assert(file->ext_ifi);
//fb_assert(relation->rel_perm->rel_file == this);
Record* const record = rpb->rpb_record;
const Format* const format = record->getFormat();
@ -368,52 +315,57 @@ bool EXT_get(thread_db* tdbb, record_param* rpb, FB_UINT64& position)
UCHAR* p = record->getData() + offset;
const ULONG l = record->getLength() - offset;
if (file->ext_ifi == NULL)
{
ERR_post(Arg::Gds(isc_io_error) << "fseek" << Arg::Str(file->ext_filename) <<
Arg::Gds(isc_io_open_err) << Arg::Unix(EBADF) <<
Arg::Gds(isc_random) << "File not opened");
}
{ //scope
MutexLockGuard g(ext_sync, FB_FUNCTION);
// hvlad: fseek will flush file buffer and degrade performance, so don't
// call it if it is not necessary. Note that we must flush file buffer if we
// do read after write
bool doSeek = false;
if (!(file->ext_flags & EXT_last_read))
{
doSeek = true;
}
else
{
SINT64 offset = FTELL64(file->ext_ifi);
if (offset < 0)
if (ext_ifi == NULL)
{
ERR_post(Arg::Gds(isc_io_error) << STRINGIZE(FTELL64) << Arg::Str(file->ext_filename) <<
Arg::Gds(isc_io_read_err) << SYS_ERR(errno));
ERR_post(Arg::Gds(isc_io_error) << "fseek" << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_open_err) << Arg::Unix(EBADF) <<
Arg::Gds(isc_random) << "File not opened");
}
doSeek = (static_cast<FB_UINT64>(offset) != position);
}
// reset both flags cause we are going to move the file pointer
file->ext_flags &= ~(EXT_last_write | EXT_last_read);
// hvlad: fseek will flush file buffer and degrade performance, so don't
// call it if it is not necessary. Note that we must flush file buffer if we
// do read after write
if (doSeek)
{
if (FSEEK64(file->ext_ifi, position, SEEK_SET) != 0)
bool doSeek = false;
if (!(ext_flags & EXT_last_read))
{
ERR_post(Arg::Gds(isc_io_error) << STRINGIZE(FSEEK64) << Arg::Str(file->ext_filename) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
doSeek = true;
}
else
{
SINT64 offset = FTELL64(ext_ifi);
if (offset < 0)
{
ERR_post(Arg::Gds(isc_io_error) << STRINGIZE(FTELL64) << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_read_err) << SYS_ERR(errno));
}
doSeek = (static_cast<FB_UINT64>(offset) != position);
}
}
if (!fread(p, l, 1, file->ext_ifi))
{
return false;
// reset both flags cause we are going to move the file pointer
ext_flags &= ~(EXT_last_write | EXT_last_read);
if (doSeek)
{
if (FSEEK64(ext_ifi, position, SEEK_SET) != 0)
{
ERR_post(Arg::Gds(isc_io_error) << STRINGIZE(FSEEK64) << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
}
}
if (!fread(p, l, 1, ext_ifi))
{
return false;
}
ext_flags |= EXT_last_read;
}
position += l;
file->ext_flags |= EXT_last_read;
// Loop thru fields setting missing fields to either blanks/zeros or the missing value
@ -449,7 +401,7 @@ bool EXT_get(thread_db* tdbb, record_param* rpb, FB_UINT64& position)
}
void EXT_modify(record_param* /*old_rpb*/, record_param* /*new_rpb*/, jrd_tra* /*transaction*/)
void ExternalFile::modify(record_param* /*old_rpb*/, record_param* /*new_rpb*/, jrd_tra* /*transaction*/)
{
/**************************************
*
@ -466,25 +418,7 @@ void EXT_modify(record_param* /*old_rpb*/, record_param* /*new_rpb*/, jrd_tra* /
}
void EXT_open(Database* dbb, ExternalFile* file)
{
/**************************************
*
* E X T _ o p e n
*
**************************************
*
* Functional description
* Open a record stream for an external file.
*
**************************************/
if (!file->ext_ifi) {
ext_fopen(dbb, file);
}
}
void EXT_store(thread_db* tdbb, record_param* rpb)
void ExternalFile::store(thread_db* tdbb, record_param* rpb)
{
/**************************************
*
@ -497,18 +431,15 @@ void EXT_store(thread_db* tdbb, record_param* rpb)
*
**************************************/
jrd_rel* relation = rpb->rpb_relation;
ExternalFile* file = relation->rel_file;
Record* record = rpb->rpb_record;
const Format* const format = record->getFormat();
if (!file->ext_ifi) {
ext_fopen(tdbb->getDatabase(), file);
}
fb_assert(ext_ifi);
// Loop thru fields setting missing fields to either blanks/zeros or the missing value
// check if file is read only if read only then post error we cannot write to this file
if (file->ext_flags & EXT_readonly)
if (ext_flags & EXT_readonly)
{
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
@ -517,7 +448,7 @@ void EXT_store(thread_db* tdbb, record_param* rpb)
ERR_post(Arg::Gds(isc_read_only_database));
else
{
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("insert") << Arg::Str(file->ext_filename) <<
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("insert") << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_write_err) <<
Arg::Gds(isc_ext_readonly_err));
}
@ -553,31 +484,32 @@ void EXT_store(thread_db* tdbb, record_param* rpb)
const UCHAR* p = record->getData() + offset;
const ULONG l = record->getLength() - offset;
MutexLockGuard g(ext_sync, FB_FUNCTION);
// hvlad: fseek will flush file buffer and degrade performance, so don't
// call it if it is not necessary. Note that we must flush file buffer if we
// do write after read
file->ext_flags &= ~EXT_last_read;
if (file->ext_ifi == NULL ||
(!(file->ext_flags & EXT_last_write) && FSEEK64(file->ext_ifi, (SINT64) 0, SEEK_END) != 0) )
ext_flags &= ~EXT_last_read;
if (ext_ifi == NULL ||
(!(ext_flags & EXT_last_write) && FSEEK64(ext_ifi, (SINT64) 0, SEEK_END) != 0) )
{
file->ext_flags &= ~EXT_last_write;
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fseek") << Arg::Str(file->ext_filename) <<
ext_flags &= ~EXT_last_write;
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fseek") << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
}
if (!fwrite(p, l, 1, file->ext_ifi))
if (!fwrite(p, l, 1, ext_ifi))
{
file->ext_flags &= ~EXT_last_write;
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fwrite") << Arg::Str(file->ext_filename) <<
ext_flags &= ~EXT_last_write;
ERR_post(Arg::Gds(isc_io_error) << Arg::Str("fwrite") << Arg::Str(ext_filename) <<
Arg::Gds(isc_io_open_err) << SYS_ERR(errno));
}
// fflush(file->ext_ifi);
file->ext_flags |= EXT_last_write;
ext_flags |= EXT_last_write;
}
void EXT_tra_attach(ExternalFile* file, jrd_tra*) noexcept
void ExternalFile::traAttach(thread_db* tdbb)
{
/**************************************
*
@ -590,11 +522,18 @@ void EXT_tra_attach(ExternalFile* file, jrd_tra*) noexcept
* Increment transactions use count.
*
**************************************/
MutexLockGuard g(ext_sync, FB_FUNCTION);
file->ext_tra_cnt++;
if (ext_tra_cnt++ == 0)
{
fb_assert(!ext_ifi);
Database* dbb = tdbb->getDatabase();
open(dbb);
fb_assert(ext_ifi);
}
}
void EXT_tra_detach(ExternalFile* file, jrd_tra*) noexcept
void ExternalFile::traDetach() noexcept
{
/**************************************
*
@ -608,11 +547,12 @@ void EXT_tra_detach(ExternalFile* file, jrd_tra*) noexcept
* external file if count is zero.
*
**************************************/
MutexLockGuard g(ext_sync, FB_FUNCTION);
file->ext_tra_cnt--;
if (!file->ext_tra_cnt && file->ext_ifi)
if (--ext_tra_cnt == 0)
{
fclose(file->ext_ifi);
file->ext_ifi = NULL;
fb_assert(ext_ifi);
fclose(ext_ifi);
ext_ifi = NULL;
}
}

View File

@ -1,48 +0,0 @@
/*
* PROGRAM: JRD Access Method
* MODULE: ext.h
* DESCRIPTION: External file access definitions
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_EXT_H
#define JRD_EXT_H
#include <stdio.h>
namespace Jrd {
// External file access block
class ExternalFile : public pool_alloc_rpt<SCHAR, type_ext>
{
public:
USHORT ext_flags; // Misc and cruddy flags
USHORT ext_tra_cnt; // How many transactions used the file
FILE* ext_ifi; // Internal file identifier
char ext_filename[1];
};
const int EXT_readonly = 1; // File could only be opened for read
const int EXT_last_read = 2; // last operation was read
const int EXT_last_write = 4; // last operation was write
} //namespace Jrd
#endif // JRD_EXT_H

View File

@ -21,29 +21,76 @@
* Contributor(s): ______________________________________.
*/
#include <stdio.h>
#include <string.h>
#include "fb_blk.h"
#include "../common/classes/alloc.h"
#include "../common/classes/locks.h"
#ifndef JRD_EXT_PROTO_H
#define JRD_EXT_PROTO_H
namespace Jrd {
class ExternalFile;
class jrd_tra;
class RecordSource;
class jrd_rel;
struct record_param;
struct bid;
}
double EXT_cardinality(Jrd::thread_db*, Jrd::jrd_rel*);
void EXT_erase(Jrd::record_param*, Jrd::jrd_tra*);
Jrd::ExternalFile* EXT_file(Jrd::jrd_rel*, const TEXT*); //, Jrd::bid*);
void EXT_fini(Jrd::jrd_rel*, bool);
bool EXT_get(Jrd::thread_db*, Jrd::record_param*, FB_UINT64&);
void EXT_modify(Jrd::record_param*, Jrd::record_param*, Jrd::jrd_tra*);
class jrd_tra;
class RecordSource;
class jrd_rel;
struct record_param;
struct bid;
class Database;
class thread_db;
void EXT_open(Jrd::Database*, Jrd::ExternalFile*);
void EXT_store(Jrd::thread_db*, Jrd::record_param*);
// External file access block
void EXT_tra_attach(Jrd::ExternalFile*, Jrd::jrd_tra*) noexcept;
void EXT_tra_detach(Jrd::ExternalFile*, Jrd::jrd_tra*) noexcept;
class ExternalFile : public pool_alloc_rpt<SCHAR, type_ext>
{
private:
ExternalFile()
: ext_flags(0), ext_tra_cnt(0), ext_ifi(nullptr)
{ }
void open(Database* dbb);
public:
static ExternalFile* create(MemoryPool& pool, const char* name)
{
ExternalFile* file = FB_NEW_RPT(pool, (strlen(name) + 1)) ExternalFile();
strcpy(file->ext_filename, name);
return file;
}
~ExternalFile()
{
fb_assert(!ext_ifi);
}
FILE* getFile()
{
return ext_ifi;
}
void traAttach(thread_db* tdbb);
void traDetach() noexcept;
double getCardinality(thread_db* tdbb, jrd_rel* relation) noexcept;
void erase(record_param*, jrd_tra*);
bool get(thread_db* tdbb, record_param* rpb, FB_UINT64& position);
void modify(record_param*, record_param*, jrd_tra*);
void store(thread_db*, record_param*);
private:
Firebird::Mutex ext_sync;
USHORT ext_flags; // Misc and cruddy flags
USHORT ext_tra_cnt; // How many transactions used the file
FILE* ext_ifi; // Internal file identifier
char ext_filename[1];
};
// ext_flags
const USHORT EXT_readonly = 1; // File could only be opened for read
const USHORT EXT_last_read = 2; // last operation was read
const USHORT EXT_last_write = 4; // last operation was write
} //namespace Jrd
#endif // JRD_EXT_PROTO_H

View File

@ -143,10 +143,7 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_
if (!MET_lookup_partner(tdbb, relation, &idx, 0))
continue;
auto referenced = MetadataCache::findRelation(tdbb, idx.idx_primary_relation);
auto referenced_relation = csb->csb_resources.registerResource(tdbb, Resource::rsc_relation,
referenced, idx.idx_primary_relation);
MET_scan_relation(tdbb, referenced);
auto referenced_relation = MetadataCache::findRelation(tdbb, idx.idx_primary_relation);
const USHORT index_id = idx.idx_primary_index;
// get the description of the primary key index
@ -171,14 +168,14 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_
const jrd_fld* referenced_field =
MET_get_field(referenced_relation, idx_desc->idx_field);
CMP_post_access(tdbb, csb,
referenced_relation->rel_security_name,
(view ? view->rel_id : 0),
referenced_relation->getSecurityName(),
(view ? view->getId() : 0),
SCL_references, obj_relations,
referenced_relation->rel_name);
referenced_relation->getName());
CMP_post_access(tdbb, csb,
referenced_field->fld_security_name, 0,
SCL_references, obj_column,
referenced_field->fld_name, referenced_relation->rel_name);
referenced_field->fld_name, referenced_relation->getName());
}
CCH_RELEASE(tdbb, &referenced_window);
@ -486,9 +483,7 @@ bool IndexCreateTask::handler(WorkItem& _item)
Database* dbb = tdbb->getDatabase();
Attachment* attachment = tdbb->getAttachment();
jrd_rel* relation = MET_relation(tdbb, m_creation->relation->rel_id);
if (!(relation->rel_flags & REL_scanned))
MET_scan_relation(tdbb, relation);
jrd_rel* relation = MetadataCache::lookup_relation_id(tdbb, m_creation->relation->getId(), false);
index_desc* idx = &item->m_idx;
jrd_tra* transaction = item->m_tra ? item->m_tra : m_creation->transaction;
@ -549,7 +544,7 @@ bool IndexCreateTask::handler(WorkItem& _item)
// if (!MET_lookup_partner(tdbb, relation, idx, m_creation->index_name)) {
// BUGCHECK(173); // msg 173 referenced index description not found
// }
partner_relation = MET_relation(tdbb, idx->idx_primary_relation);
partner_relation = MetadataCache::lookup_relation_id(tdbb, idx->idx_primary_relation, false);
partner_index_id = idx->idx_primary_index;
}
@ -558,7 +553,7 @@ bool IndexCreateTask::handler(WorkItem& _item)
fb_assert(!m_exprBlob.isEmpty());
CompilerScratch* csb = NULL;
Jrd::ContextPoolHolder context(tdbb, attachment->createPool());
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
idx->idx_expression = static_cast<ValueExprNode*> (MET_parse_blob(tdbb, relation, &m_exprBlob,
&csb, &idx->idx_expression_statement, false, false));
@ -850,10 +845,10 @@ void IDX_create_index(thread_db* tdbb,
Database* dbb = tdbb->getDatabase();
Jrd::Attachment* attachment = tdbb->getAttachment();
if (relation->rel_file)
if (relation->getExtFile())
{
ERR_post(Arg::Gds(isc_no_meta_update) <<
Arg::Gds(isc_extfile_uns_op) << Arg::Str(relation->rel_name));
Arg::Gds(isc_extfile_uns_op) << Arg::Str(relation->getName()));
}
else if (relation->isVirtual())
{
@ -974,13 +969,9 @@ void IDX_create_index(thread_db* tdbb,
if ((relation->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0))
{
IndexLock* idx_lock = CMP_get_index_lock(tdbb, relation, idx->idx_id);
IndexLock* idx_lock = relation->rel_perm->getIndexLock(tdbb, idx->idx_id);
if (idx_lock)
{
++idx_lock->idl_count;
if (idx_lock->idl_count == 1)
LCK_lock(tdbb, idx_lock->idl_lock, LCK_SR, LCK_WAIT);
}
idx_lock->lockShared(tdbb);
}
}
@ -1017,7 +1008,7 @@ IndexBlock* IDX_create_index_block(thread_db* tdbb, jrd_rel* relation, USHORT id
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0)
Lock(tdbb, sizeof(SLONG), LCK_expression, index_block, index_block_flush);
index_block->idb_lock = lock;
lock->setKey((relation->rel_id << 16) | index_block->idb_id);
lock->setKey((relation->getId() << 16) | index_block->idb_id);
return index_block;
}
@ -1047,9 +1038,9 @@ void IDX_delete_index(thread_db* tdbb, jrd_rel* relation, USHORT id)
if ((relation->rel_flags & REL_temp_conn) && (relation->getPages(tdbb)->rel_instance_id != 0) &&
tree_exists)
{
HazardPtr<IndexLock> idx_lock = relation->getIndexLock(tdbb, id);
IndexLock* idx_lock = relation->rel_perm->getIndexLock(tdbb, id);
if (idx_lock)
idx_lock->idl_lock.leave245(tdbb);
idx_lock->unlockAll(tdbb);
}
}
@ -1083,9 +1074,9 @@ void IDX_delete_indices(thread_db* tdbb, jrd_rel* relation, RelationPages* relPa
if (is_temp && tree_exists)
{
HazardPtr<IndexLock> idx_lock = relation->getIndexLock(tdbb, i);
IndexLock* idx_lock = relation->rel_perm->getIndexLock(tdbb, i);
if (idx_lock)
idx_lock->idl_lock.releaseLock(tdbb, ExistenceLock::ReleaseMethod::Normal);
idx_lock->unlockAll(tdbb);
}
}
@ -1738,7 +1729,7 @@ static idx_e check_foreign_key(thread_db* tdbb,
if (!MET_lookup_partner(tdbb, relation, idx, 0))
return result;
jrd_rel* partner_relation(tdbb);
jrd_rel* partner_relation = nullptr;
USHORT index_id = 0;
if (idx->idx_flags & idx_foreign)
@ -1746,7 +1737,7 @@ static idx_e check_foreign_key(thread_db* tdbb,
partner_relation = MetadataCache::findRelation(tdbb, idx->idx_primary_relation);
index_id = idx->idx_primary_index;
result = check_partner_index(tdbb, relation, record, transaction, idx,
partner_relation.getPointer(), index_id);
partner_relation, index_id);
}
else if (idx->idx_flags & (idx_primary | idx_unique))
{
@ -1762,15 +1753,15 @@ static idx_e check_foreign_key(thread_db* tdbb,
if ((relation->rel_flags & REL_temp_conn) && (partner_relation->rel_flags & REL_temp_tran))
{
jrd_rel::RelPagesSnapshot pagesSnapshot(tdbb, partner_relation.getPointer());
partner_relation->fillPagesSnapshot(pagesSnapshot, true);
RelationPermanent::RelPagesSnapshot pagesSnapshot(tdbb, partner_relation->rel_perm);
partner_relation->rel_perm->fillPagesSnapshot(pagesSnapshot, true);
for (FB_SIZE_T i = 0; i < pagesSnapshot.getCount(); i++)
{
RelationPages* partnerPages = pagesSnapshot[i];
tdbb->tdbb_temp_traid = partnerPages->rel_instance_id;
if ( (result = check_partner_index(tdbb, relation, record,
transaction, idx, partner_relation.getPointer(), index_id)) )
transaction, idx, partner_relation, index_id)) )
{
break;
}
@ -1783,7 +1774,7 @@ static idx_e check_foreign_key(thread_db* tdbb,
else
{
if ( (result = check_partner_index(tdbb, relation, record,
transaction, idx, partner_relation.getPointer(), index_id)) )
transaction, idx, partner_relation, index_id)) )
{
break;
}
@ -1796,7 +1787,7 @@ static idx_e check_foreign_key(thread_db* tdbb,
if (idx->idx_flags & idx_foreign)
context.setErrorLocation(relation, idx->idx_id);
else
context.setErrorLocation(partner_relation.getPointer(), index_id);
context.setErrorLocation(partner_relation, index_id);
}
return result;
@ -1854,7 +1845,7 @@ static idx_e check_partner_index(thread_db* tdbb,
{
if (idx_desc->idx_itype >= idx_first_intl_string)
{
HazardPtr<TextType> textType = INTL_texttype_lookup(tdbb, INTL_INDEX_TO_TEXT(idx_desc->idx_itype));
TextType* textType = INTL_texttype_lookup(tdbb, INTL_INDEX_TO_TEXT(idx_desc->idx_itype));
if (textType->getFlags() & TEXTTYPE_SEPARATE_UNIQUE)
{

View File

@ -41,11 +41,11 @@ namespace Jrd
void IDX_check_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_rel*, Jrd::jrd_rel*);
bool IDX_check_master_types (Jrd::thread_db*, Jrd::index_desc&, Jrd::jrd_rel*, int&);
void IDX_create_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*, const TEXT*,
void IDX_create_index(Jrd::thread_db*, const Jrd::RelationPermanent*, Jrd::index_desc*, const TEXT*,
USHORT*, Jrd::jrd_tra*, Jrd::SelectivityList&);
Jrd::IndexBlock* IDX_create_index_block(Jrd::thread_db*, Jrd::jrd_rel*, USHORT);
void IDX_delete_index(Jrd::thread_db*, Jrd::jrd_rel*, USHORT);
void IDX_delete_indices(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::RelationPages*);
void IDX_delete_index(Jrd::thread_db*, Jrd::RelationPermanent*, USHORT);
void IDX_delete_indices(Jrd::thread_db*, Jrd::RelationPermanent*, Jrd::RelationPages*);
void IDX_erase(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*);
void IDX_garbage_collect(Jrd::thread_db*, Jrd::record_param*, Jrd::RecordStack&, Jrd::RecordStack&);
void IDX_modify(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*, Jrd::jrd_tra*);

View File

@ -208,6 +208,22 @@ namespace
{ 0, 0, 0, 0 }
};
unsigned getLatestFormat(thread_db* tdbb, int relId, int maxFieldId)
{
const auto* relation = MetadataCache::lookupRelation(tdbb, relId);
fb_assert(relation && relation->rel_formats);
fb_assert(relation->rel_formats->count());
const auto formatNumber = relation->rel_formats->count() - 1;
fb_assert(formatNumber < MAX_TABLE_VERSIONS);
const auto format = (*relation->rel_formats)[formatNumber];
fb_assert(format->fmt_count == maxFieldId);
fb_assert(format->fmt_version == formatNumber);
return formatNumber;
}
bool getCharsetByTextType(SSHORT& charSet, const USHORT subType)
{
switch (subType)
@ -751,10 +767,7 @@ void INI_format(thread_db* tdbb, const string& charset)
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_TYPE] == rel_persistent)
{
auto rel = MetadataCache::findRelation(tdbb, relfld[RFLD_R_ID]);
DPM_create_relation(tdbb, rel.getPointer());
}
DPM_create_relation(tdbb, MetadataCache::lookup_relation_id(tdbb, relfld[RFLD_R_ID]));
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
;
@ -969,16 +982,9 @@ void INI_init(thread_db* tdbb)
const int* fld;
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
extern CacheObject* TRAP;
const auto id = relfld[RFLD_R_ID];
//fprintf(stderr, "INI_init %d %s\n", id, names[relfld[RFLD_R_NAME]]);
jrd_rel* relation = MetadataCache::findRelation(tdbb, id);
if (id == 7) TRAP = relation.getPointer();
const bool isPersistent = (relfld[RFLD_R_TYPE] == rel_persistent);
auto* relation = MetadataCache::lookupRelation(tdbb, relfld[RFLD_R_ID]);
relation->rel_flags |= REL_system;
relation->rel_flags |= MET_get_rel_flags_from_TYPE(relfld[RFLD_R_TYPE]);
relation->rel_name = names[relfld[RFLD_R_NAME]];
@ -994,6 +1000,8 @@ void INI_init(thread_db* tdbb)
}
}
jrd_rel* relVers = FB_NEW_POOL(relation->getPool()) jrd_rel(relation->getPool(), relation);
HalfStaticArray<const char*, 64> fieldNames;
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
{
@ -1001,7 +1009,7 @@ void INI_init(thread_db* tdbb)
}
const auto fields = vec<jrd_fld*>::newVector(*pool, fieldNames.getCount());
relation->rel_fields = fields;
relVers->rel_fields = fields;
ULONG fieldPos = 0;
for (auto iter = fields->begin(); iter != fields->end(); ++iter)
@ -1014,12 +1022,11 @@ void INI_init(thread_db* tdbb)
relation->rel_formats = vec<Format*>::newVector(*pool, 1);
const auto majorVersion = ODS_VERSION;
const auto dbMinorVersion = dbb->dbb_ods_version ? dbb->dbb_minor_version : ODS_CURRENT;
// We need only the latest format for virtual tables
auto minorVersion = isPersistent ? ODS_RELEASED : ODS_CURRENT;
unsigned formatNumber = 0, currentFormat = 0;
MetadataCache* mdc = tdbb->getDatabase()->dbb_mdc;
while (minorVersion <= ODS_CURRENT)
{
bool newFormat = false;
@ -1046,9 +1053,6 @@ void INI_init(thread_db* tdbb)
format->fmt_version = formatNumber;
format->fmt_length = FLAG_BYTES(format->fmt_count);
if (minorVersion == dbb->dbb_minor_version)
currentFormat = formatNumber;
relation->rel_formats->resize(formatNumber + 1);
(*relation->rel_formats)[formatNumber] = format;
@ -1086,13 +1090,16 @@ void INI_init(thread_db* tdbb)
format->fmt_length += desc->dsc_length;
}
if (minorVersion == dbMinorVersion)
currentFormat = formatNumber;
minorVersion++;
formatNumber++;
}
fb_assert(currentFormat < relation->rel_formats->count());
relation->rel_current_fmt = currentFormat;
relation->rel_current_format = (*relation->rel_formats)[currentFormat];
relVers->rel_current_fmt = currentFormat;
relVers->rel_current_format = (*relation->rel_formats)[currentFormat];
}
}
@ -1290,7 +1297,7 @@ void INI_upgrade(thread_db* tdbb)
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion)
DPM_create_relation(tdbb, MET_relation(tdbb, relfld[RFLD_R_ID]));
DPM_create_relation(tdbb, MetadataCache::lookup_relation_id(tdbb, relfld[RFLD_R_ID]));
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
;
@ -1333,17 +1340,12 @@ void INI_upgrade(thread_db* tdbb)
{
// New format number is the latest we're aware of
const auto relation = MET_relation(tdbb, relId);
fb_assert(relation->rel_formats->count());
const unsigned formatNumber = relation->rel_formats->count() - 1;
fb_assert(formatNumber < MAX_TABLE_VERSIONS);
FOR(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_ID = relId
{
MODIFY REL USING
REL.RDB$FORMAT = formatNumber;
REL.RDB$FORMAT = getLatestFormat(tdbb, relId, fieldId);
END_MODIFY
}
END_FOR
@ -1435,7 +1437,7 @@ void INI_upgrade(thread_db* tdbb)
{
if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion)
{
const auto relation = MET_relation(tdbb, relfld[RFLD_R_ID]);
const auto relation = MetadataCache::lookupRelation(tdbb, relfld[RFLD_R_ID]);
if (relation && relation->getBasePages()->rel_pages)
DPM_delete_relation(tdbb, relation);
}
@ -1502,253 +1504,7 @@ void INI_upgrade(thread_db* tdbb)
if (invalidate && dbb->dbb_relations.get(relName, relation))
{
MET_dsql_cache_use(tdbb, SYM_relation, relName);
relation->rel_flags |= REL_dropped;
dbb->dbb_relations.remove(relName);
}
}
}
}
// The caller used an UCHAR* to store the acl, it was converted to TEXT* to
// be passed to this function, only to be converted to UCHAR* to be passed
// to BLB_put_segment. Therefore, "acl" was changed to UCHAR* as param.
static void add_security_to_sys_rel(thread_db* tdbb,
AutoRequest& reqAddSC,
AutoRequest& reqModObjSC,
AutoRequest& reqInsUserPriv,
const MetaName& user_name,
const TEXT* rel_name,
const USHORT acl_length,
const UCHAR* acl)
{
/**************************************
*
* a d d _ s e c u r i t y _ t o _ s y s _ r e l
*
**************************************
*
* Functional description
*
* Add security to system relations. Only the owner of the
* database has SELECT/INSERT/UPDATE/DELETE privileges on
* any system relations. Any other users only has SELECT
* privilege.
*
**************************************/
MetaName security_class, default_class;
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
security_class.printf("%s%" SQUADFORMAT, SQL_SECCLASS_PREFIX,
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, SQL_SECCLASS_GENERATOR), false, 1));
default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS,
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false, 1));
add_security_class(tdbb, reqAddSC, security_class, acl_length, acl);
add_security_class(tdbb, reqAddSC, default_class, acl_length, acl);
FOR(REQUEST_HANDLE reqModObjSC) REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_NAME EQ rel_name
{
MODIFY REL USING
REL.RDB$SECURITY_CLASS.NULL = FALSE;
PAD(security_class.c_str(), REL.RDB$SECURITY_CLASS);
REL.RDB$DEFAULT_CLASS.NULL = FALSE;
PAD(default_class.c_str(), REL.RDB$DEFAULT_CLASS);
END_MODIFY
}
END_FOR
for (int cnt = 0; cnt < 6; cnt++)
{
STORE(REQUEST_HANDLE reqInsUserPriv) PRIV IN RDB$USER_PRIVILEGES
switch (cnt)
=======
if (relfld[RFLD_R_ODS] > odsVersion)
>>>>>>> master
{
store_relation(tdbb, relId, relName, fieldId, relType, handle, relSec);
}
else if (newFormat)
{
// New format number is the latest we're aware of
const auto relation = MET_relation(tdbb, relId);
fb_assert(relation->rel_formats->count());
const unsigned formatNumber = relation->rel_formats->count() - 1;
fb_assert(formatNumber < MAX_TABLE_VERSIONS);
FOR(REQUEST_HANDLE handle3 TRANSACTION_HANDLE transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_ID = relId
{
MODIFY REL USING
REL.RDB$FORMAT = formatNumber;
END_MODIFY
}
END_FOR
// Schedule metadata cache to be updated at the commit time
dsc desc;
desc.makeText(static_cast<USHORT>(strlen(relName)), CS_METADATA,
(UCHAR*) relName);
DFW_post_work(transaction, dfw_update_format, &desc, 0);
}
}
}
NonRelationSecurity nonRelSec(ownerName, reqAddSC, false);
// Create global fields added after the original minor ODS
context = "domains";
handle.reset();
for (const gfld* gfield = gfields; gfield->gfld_name; gfield++)
{
if (gfield->gfld_ods_version > odsVersion)
store_global_field(tdbb, gfield, handle, nonRelSec);
}
// Create new system indexes
context = "indices";
store_indices(tdbb, odsVersion);
// Create new system triggers and their trigger messages
context = "triggers";
handle.reset();
for (const jrd_trg* trigger = triggers; trigger->trg_relation; ++trigger)
{
if (trigger->trg_ods_version > odsVersion)
store_trigger(tdbb, trigger, handle);
}
context = "trigger messages";
handle.reset();
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
{
if (message->trg_ods_version > odsVersion)
store_message(tdbb, message, handle);
}
// Create new system generators
context = "generators";
handle.reset();
for (const gen* generator = generators; generator->gen_name; generator++)
{
if (generator->gen_ods_version > odsVersion)
store_generator(tdbb, generator, handle, nonRelSec);
}
// Create new system packages
// Reset nonRelSec for package permissions, it should be its last usage in this function
new(&nonRelSec) NonRelationSecurity(ownerName, reqAddSC, true);
context = "packages";
store_packages(tdbb, nonRelSec, odsVersion);
// There are no new built-in charsets and collations introduced in ODS 13.1.
// But if it happens in some future minor ODS, the corresponding INTL structures
// should have the ODS field added and here we need code that conditionally adds
// the missing charsets/collations.
//
// The same about the new types being introduced in minor ODS versions.
TRA_commit(tdbb, transaction, false);
}
catch (const Exception& ex)
{
TRA_rollback(tdbb, transaction, false, true);
// Delete relations we've just created
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
if (relfld[RFLD_R_TYPE] == rel_persistent && relfld[RFLD_R_ODS] > odsVersion)
{
const auto relation = MET_relation(tdbb, relfld[RFLD_R_ID]);
if (relation && relation->getBasePages()->rel_pages)
DPM_delete_relation(tdbb, relation);
}
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
;
}
string msg;
msg.printf("Database: %s\n\t"
"Failed upgrading ODS from version %u.%u to version %u.%u",
attachment->att_filename.c_str(),
majorVersion, minorVersion, majorVersion, ODS_CURRENT);
iscLogException(msg.c_str(), ex);
if (context)
{
Arg::StatusVector error(ex);
error.prepend(Arg::Gds(isc_ods_upgrade_err) << Arg::Str(context));
error.raise();
}
throw;
}
// If the database was successfully updated, mark it with the current minor ODS
win window(HEADER_PAGE_NUMBER);
auto header = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
CCH_MARK(tdbb, &window);
dbb->dbb_minor_version = header->hdr_ods_minor = ODS_CURRENT;
CCH_RELEASE(tdbb, &window);
string msg;
msg.printf("Database: %s\n\t"
"Successfully upgraded ODS from version %u.%u to version %u.%u",
attachment->att_filename.c_str(),
majorVersion, minorVersion, majorVersion, ODS_CURRENT);
gds__log(msg.c_str());
// Invalidate new/modified relations in the DSQL metadata cache,
// thus forcing them to be reloaded on demand
if (const auto dbb = attachment->att_dsql_instance)
{
for (const int* relfld = relfields; relfld[RFLD_R_NAME]; relfld = fld + 1)
{
bool invalidate = false;
if (relfld[RFLD_R_ODS] > odsVersion)
invalidate = true;
for (fld = relfld + RFLD_RPT; fld[RFLD_F_NAME]; fld += RFLD_F_LENGTH)
{
if (fld[RFLD_F_ODS] > odsVersion)
invalidate = true;
}
// Code below is the same as METD_drop_relation() but without a transaction
const auto relName = names[relfld[RFLD_R_NAME]];
dsql_rel* relation;
if (invalidate && dbb->dbb_relations.get(relName, relation))
{
MET_dsql_cache_use(tdbb, SYM_relation, relName);
MetadataCache::dsql_cache_use(tdbb, SYM_relation, relName);
relation->rel_flags |= REL_dropped;
dbb->dbb_relations.remove(relName);
}
@ -2026,7 +1782,8 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion)
for (int n = 0; n < SYSTEM_INDEX_COUNT; n++)
{
const ini_idx_t* index = &indices[n];
const auto relation = MET_relation(tdbb, index->ini_idx_relid);
const auto* relVers = MetadataCache::lookup_relation_id(tdbb, index->ini_idx_relid);
const auto* relation = relVers->rel_perm;
if (odsVersion && index->ini_idx_ods <= odsVersion)
continue;
@ -2065,7 +1822,7 @@ static void store_indices(thread_db* tdbb, USHORT odsVersion)
STORE(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction)
Y IN RDB$INDEX_SEGMENTS
{
jrd_fld* field = (*relation->rel_fields)[segment->ini_idx_rfld_id];
jrd_fld* field = (*relVers->rel_fields)[segment->ini_idx_rfld_id];
Y.RDB$FIELD_POSITION = position;
PAD(X.RDB$INDEX_NAME, Y.RDB$INDEX_NAME);
@ -2244,7 +2001,7 @@ static void store_relation(thread_db* tdbb,
X.RDB$DEFAULT_CLASS.NULL = FALSE;
X.RDB$FIELD_ID = fieldId;
X.RDB$FORMAT = 0;
X.RDB$FORMAT = getLatestFormat(tdbb, relId, fieldId);
X.RDB$SYSTEM_FLAG = RDB_system;
X.RDB$DBKEY_LENGTH = 8;
}

View File

@ -93,6 +93,7 @@
#include "firebird.h"
#include <string.h>
#include <stdio.h>
#include "../jrd/CharSetContainer.h"
#include "../jrd/jrd.h"
#include "../jrd/req.h"
#include "../jrd/val.h"
@ -139,7 +140,7 @@ static void lookup_texttype(texttype* tt, const SubtypeInfo* info);
static GlobalPtr<Mutex> createCollationMtx;
// Classes and structures used internally to this file and intl implementation
HazardPtr<CharSetContainer> CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
CharSetContainer* CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
{
/**************************************
*
@ -173,18 +174,19 @@ HazardPtr<CharSetContainer> CharSetContainer::lookupCharset(thread_db* tdbb, USH
}
CharSetContainer* CharSetContainer::create(thread_db* tdbb, MetaId id)
CharSetContainer* CharSetContainer::create(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
{
SubtypeInfo info;
if (lookupInternalCharSet(id, &info) || MET_get_char_coll_subtype_info(tdbb, id, &info))
{
Database* dbb = tdbb->getDatabase();
CharSetContainer* csc = FB_NEW_POOL(*dbb->dbb_permanent) CharSetContainer(*dbb->dbb_permanent, id, &info);
dbb->dbb_mdc->setCharSet(tdbb, id, csc);
cs = dbb->dbb_mdc->getCharSet(tdbb, id);
dbb->dbb_mdc->makeCharSet(tdbb, id, csc);
return dbb->dbb_mdc->getCharSet(tdbb, id);
}
else
ERR_post(Arg::Gds(isc_text_subtype) << Arg::Num(ttype));
ERR_post(Arg::Gds(isc_text_subtype) << Arg::Num(id));
}
@ -256,7 +258,7 @@ Lock* CharSetContainer::createCollationLock(thread_db* tdbb, USHORT ttype, void*
}
CharSetContainer::CharSetContainer(MemoryPool& p, USHORT cs_id, const SubtypeInfo* info)
: charset_collations(p),
: PermanentStorage(p),
cs(NULL)
{
charset* csL = FB_NEW_POOL(p) charset;
@ -286,34 +288,19 @@ CsConvert CharSetContainer::lookupConverter(thread_db* tdbb, CHARSET_ID toCsId)
return CsConvert(cs->getStruct(), toCs->getStruct());
}
Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
Collation* CharSetVers::lookupCollation(thread_db* tdbb, USHORT tt_id)
{
const USHORT id = TTYPE_TO_COLLATION(tt_id);
Collation* coll(FB_FUNCTION);
if (charset_collations.load(tdbb, id, coll))
{
if (!coll->obsolete)
return coll;
}
if (Collation* coll = charset_collations[id])
return coll;
CheckoutLockGuard guard(tdbb, createCollationMtx, FB_FUNCTION); // do we need it ?
Collation* to_delete(FB_FUNCTION);
if (charset_collations.load(tdbb, id, coll))
{
if (!coll->obsolete)
return coll;
to_delete = coll;
bool rc = charset_collations.replace(tdbb, id, coll, nullptr);
fb_assert(rc);
}
SubtypeInfo info;
if (MET_get_char_coll_subtype_info(tdbb, tt_id, &info))
{
CharSet* charset = INTL_charset_lookup(tdbb, TTYPE_TO_CHARSET(tt_id));
CharSet* charset = perm->getCharSet();
if (TTYPE_TO_CHARSET(tt_id) != CS_METADATA)
{
@ -334,8 +321,8 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
lookup_texttype(tt, &info);
if (charset_collations.getCount(tdbb) <= id)
charset_collations.grow(tdbb, id + 1);
if (charset_collations.getCount() <= id)
charset_collations.grow(id + 1);
fb_assert((tt->texttype_canonical_width == 0 && tt->texttype_fn_canonical == NULL) ||
(tt->texttype_canonical_width != 0 && tt->texttype_fn_canonical != NULL));
@ -358,45 +345,15 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
tt.release();
// we don't need a lock in the charset
if (id != 0)
{
collation->existenceLock = CharSetContainer::createCollationLock(tdbb, tt_id, collation);
fb_assert(collation->useCount == 0);
fb_assert(!collation->obsolete);
}
if (id != 0)
{
LCK_lock(tdbb, collation->existenceLock, LCK_SR, LCK_WAIT);
// as we just obtained SR lock for new collation instance
// we could safely delete obsolete instance
if (to_delete)
to_delete->destroy(tdbb);
}
//
// We did not delete "to_delete" when id == 0. Why??????????????????
//
coll = charset_collations.store(tdbb, id, collation);
charset_collations[id] = collation;
}
else
{
if (to_delete)
{
LCK_lock(tdbb, to_delete->existenceLock, LCK_SR, LCK_WAIT);
to_delete->destroy(tdbb);
}
ERR_post(Arg::Gds(isc_text_subtype) << Arg::Num(tt_id));
}
return coll;
return charset_collations[id];
}
/*
void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id)
{
const USHORT id = TTYPE_TO_COLLATION(tt_id);
@ -431,7 +388,7 @@ void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id)
LCK_release(tdbb, lock);
}
}
*/
static void lookup_texttype(texttype* tt, const SubtypeInfo* info)
{
@ -443,16 +400,14 @@ static void lookup_texttype(texttype* tt, const SubtypeInfo* info)
void Jrd::MetadataCache::releaseIntlObjects(thread_db* tdbb)
{
for (auto cs : mdc_charsets.snapshot())
{
if (cs)
cs->release(tdbb);
}
mdc_charsets.cleanup();
}
void Jrd::MetadataCache::destroyIntlObjects(thread_db* tdbb)
{
mdc_charsets.cleanup();
/*
for (FB_SIZE_T i = 0; i < mdc_charsets.getCount(tdbb); i++)
{
HazardPtr<CharSetContainer> cs;
@ -461,7 +416,7 @@ void Jrd::MetadataCache::destroyIntlObjects(thread_db* tdbb)
cs->destroy(tdbb);
mdc_charsets.store(tdbb, i, nullptr);
}
}
} */
}
@ -603,7 +558,7 @@ int INTL_compare(thread_db* tdbb, const dsc* pText1, const dsc* pText2, ErrorFun
}
}
HazardPtr<TextType> obj = INTL_texttype_lookup(tdbb, compare_type);
TextType* obj = INTL_texttype_lookup(tdbb, compare_type);
return obj->compare(length1, p1, length2, p2);
}
@ -719,7 +674,7 @@ CsConvert INTL_convert_lookup(thread_db* tdbb, CHARSET_ID to_cs, CHARSET_ID from
fb_assert(from_cs != CS_dynamic);
fb_assert(to_cs != CS_dynamic);
HazardPtr<CharSetContainer> charset = CharSetContainer::lookupCharset(tdbb, from_cs);
CharSetContainer* charset = CharSetContainer::lookupCharset(tdbb, from_cs);
return charset->lookupConverter(tdbb, to_cs);
}
@ -951,7 +906,7 @@ USHORT INTL_key_length(thread_db* tdbb, USHORT idxType, USHORT iLength)
key_length = iLength;
else
{
HazardPtr<TextType> obj = INTL_texttype_lookup(tdbb, ttype);
TextType* obj = INTL_texttype_lookup(tdbb, ttype);
key_length = obj->key_length(iLength);
}
@ -989,7 +944,7 @@ CharSet* INTL_charset_lookup(thread_db* tdbb, USHORT parm1)
* <never> - if error
*
**************************************/
HazardPtr<CharSetContainer> csc = CharSetContainer::lookupCharset(tdbb, parm1);
CharSetContainer* csc = CharSetContainer::lookupCharset(tdbb, parm1);
return csc->getCharSet();
}
@ -1021,15 +976,19 @@ Collation* INTL_texttype_lookup(thread_db* tdbb, USHORT parm1)
if (parm1 == ttype_dynamic)
parm1 = MAP_CHARSET_TO_TTYPE(tdbb->getCharSet());
HazardPtr<CharSetContainer> csc = CharSetContainer::lookupCharset(tdbb, parm1);
auto* perm = MetadataCache::lookupCharset(tdbb, TTYPE_TO_CHARSET(parm1));
if (!perm)
return nullptr;
return csc->lookupCollation(tdbb, parm1);
auto* vers = perm->getObject(tdbb);
return vers ? vers->lookupCollation(tdbb, TTYPE_TO_COLLATION(parm1)) : nullptr;
}
void INTL_texttype_unload(thread_db* tdbb, USHORT ttype)
/*void INTL_texttype_unload(thread_db* tdbb, USHORT ttype)
{
/**************************************
**************************************
*
* I N T L _ t e x t t y p e _ u n l o a d
*
@ -1038,14 +997,14 @@ void INTL_texttype_unload(thread_db* tdbb, USHORT ttype)
* Functional description
* Unload a collation from memory.
*
**************************************/
**************************************
SET_TDBB(tdbb);
HazardPtr<CharSetContainer> csc = CharSetContainer::lookupCharset(tdbb, ttype);
CharSetContainer* csc = CharSetContainer::lookupCharset(tdbb, ttype);
if (csc)
csc->unloadCollation(tdbb, ttype);
}
*/
bool INTL_texttype_validate(Jrd::thread_db* tdbb, const SubtypeInfo* info)
{

View File

@ -50,7 +50,7 @@ bool INTL_defined_type(Jrd::thread_db*, USHORT);
USHORT INTL_key_length(Jrd::thread_db*, USHORT, USHORT);
Jrd::CharSet* INTL_charset_lookup(Jrd::thread_db* tdbb, USHORT parm1);
Jrd::Collation* INTL_texttype_lookup(Jrd::thread_db* tdbb, USHORT parm1);
void INTL_texttype_unload(Jrd::thread_db*, USHORT);
//void INTL_texttype_unload(Jrd::thread_db*, USHORT);
bool INTL_texttype_validate(Jrd::thread_db*, const SubtypeInfo*);
void INTL_pad_spaces(Jrd::thread_db*, dsc*, UCHAR*, ULONG);
USHORT INTL_string_to_key(Jrd::thread_db*, USHORT, const dsc*, dsc*, USHORT);

View File

@ -2126,8 +2126,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
// load DDL triggers
mdc->load_ddl_triggers(tdbb);
TrigVectorPtr* trig_connect = dbb->dbb_mdc->getTriggers(DB_TRIGGER_CONNECT | TRIGGER_TYPE_DB);
if (trig_connect && trig_connect->load() && !trig_connect->load()->isEmpty(tdbb))
auto* trig_connect = dbb->dbb_mdc->getTriggers(DB_TRIGGER_CONNECT | TRIGGER_TYPE_DB);
if (trig_connect && *trig_connect)
{
// Start a transaction to execute ON CONNECT triggers.
// Ensure this transaction can't trigger auto-sweep.
@ -8202,11 +8202,11 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
{
try
{
TrigVectorPtr* trig_disconnect = dbb->dbb_mdc->getTriggers(DB_TRIGGER_CONNECT | TRIGGER_TYPE_DB);
auto* trig_disconnect = dbb->dbb_mdc->getTriggers(DB_TRIGGER_CONNECT | TRIGGER_TYPE_DB);
if (!forcedPurge &&
!(attachment->att_flags & ATT_no_db_triggers) &&
trig_disconnect && trig_disconnect->load() && !trig_disconnect->load()->isEmpty(tdbb))
trig_disconnect && *trig_disconnect)
{
ThreadStatusGuard temp_status(tdbb);
@ -9686,7 +9686,7 @@ void JRD_cancel_operation(thread_db* /*tdbb*/, Jrd::Attachment* attachment, int
}
}
/* ????????????
bool TrigVector::hasActive() const
{
for (auto t : snapshot())
@ -9723,3 +9723,5 @@ void TrigVector::release(thread_db* tdbb)
delete this;
}
}
*/

View File

@ -32,6 +32,7 @@
#define JRD_JRD_H
#include "../common/gdsassert.h"
#include "../jrd/tdbb.h"
#include "../common/dsc.h"
#include "../jrd/err_proto.h"
#include "../jrd/jrd_proto.h"
@ -62,9 +63,6 @@
#include "../jrd/Attachment.h"
#include "firebird/Interface.h"
#include <cds/threading/model.h> // cds::threading::Manager
#define BUGCHECK(number) ERR_bugcheck(number, __FILE__, __LINE__)
#define SOFT_BUGCHECK(number) ERR_soft_bugcheck(number, __FILE__, __LINE__)
#define CORRUPT(number) ERR_corrupt(number)
#define IBERROR(number) ERR_error(number)
@ -205,445 +203,6 @@ const USHORT WIN_garbage_collector = 4; // garbage collector's window
const USHORT WIN_garbage_collect = 8; // scan left a page for garbage collector
#ifdef USE_ITIMER
class TimeoutTimer final :
public Firebird::RefCntIface<Firebird::ITimerImpl<TimeoutTimer, Firebird::CheckStatusWrapper> >
{
public:
explicit TimeoutTimer()
: m_started(0),
m_expired(false),
m_value(0),
m_error(0)
{ }
// ITimer implementation
void handler();
bool expired() const
{
return m_expired;
}
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 m_started;
bool m_expired;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#else
class TimeoutTimer : public Firebird::RefCounted
{
public:
explicit TimeoutTimer()
: m_start(0),
m_value(0),
m_error(0)
{ }
bool expired() const;
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// clock value when timer will expire
bool getExpireClock(SINT64& clock) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_start = 0;
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 currTime() const
{
return fb_utils::query_performance_counter() * 1000 / fb_utils::query_performance_frequency();
}
SINT64 m_start;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#endif // USE_ITIMER
// Thread specific database block
// tdbb_flags
const ULONG TDBB_sweeper = 1; // Thread sweeper or garbage collector
const ULONG TDBB_no_cache_unwind = 2; // Don't unwind page buffer cache
const ULONG TDBB_backup_write_locked = 4; // BackupManager has write lock on LCK_backup_database
const ULONG TDBB_stack_trace_done = 8; // PSQL stack trace is added into status-vector
const ULONG TDBB_dont_post_dfw = 16; // dont post DFW tasks as deferred work is performed now
const ULONG TDBB_sys_error = 32; // error shouldn't be handled by the looper
const ULONG TDBB_verb_cleanup = 64; // verb cleanup is in progress
const ULONG TDBB_use_db_page_space = 128; // use database (not temporary) page space in GTT operations
const ULONG TDBB_detaching = 256; // detach is in progress
const ULONG TDBB_wait_cancel_disable = 512; // don't cancel current waiting operation
const ULONG TDBB_cache_unwound = 1024; // page cache was unwound
const ULONG TDBB_reset_stack = 2048; // stack should be reset after stack overflow exception
const ULONG TDBB_dfw_cleanup = 4096; // DFW cleanup phase is active
const ULONG TDBB_repl_in_progress = 8192; // Prevent recursion in replication
const ULONG TDBB_replicator = 16384; // Replicator
class thread_db : public Firebird::ThreadData
{
const static int QUANTUM = 100; // Default quantum
const static int SWEEP_QUANTUM = 10; // Make sweeps less disruptive
private:
MemoryPool* defaultPool;
void setDefaultPool(MemoryPool* p)
{
defaultPool = p;
}
friend class Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool>;
Database* database;
Attachment* attachment;
jrd_tra* transaction;
Request* request;
RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat;
public:
explicit thread_db(FbStatusVector* status)
: ThreadData(ThreadData::tddDBB),
defaultPool(NULL),
database(NULL),
attachment(NULL),
transaction(NULL),
request(NULL),
tdbb_status_vector(status),
tdbb_quantum(QUANTUM),
tdbb_flags(0),
tdbb_temp_traid(0),
tdbb_bdbs(*getDefaultMemoryPool()),
tdbb_thread(Firebird::ThreadSync::getThread("thread_db"))
{
reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy();
fb_utils::init_status(tdbb_status_vector);
}
~thread_db()
{
resetStack();
#ifdef DEV_BUILD
for (FB_SIZE_T n = 0; n < tdbb_bdbs.getCount(); ++n)
{
fb_assert(tdbb_bdbs[n] == NULL);
}
#endif
}
FbStatusVector* tdbb_status_vector;
SLONG tdbb_quantum; // Cycles remaining until voluntary schedule
ULONG tdbb_flags;
TraNumber tdbb_temp_traid; // current temporary table scope
// BDB's held by thread
Firebird::HalfStaticArray<BufferDesc*, 16> tdbb_bdbs;
Firebird::ThreadSync* tdbb_thread;
MemoryPool* getDefaultPool()
{
return defaultPool;
}
Database* getDatabase()
{
return database;
}
const Database* getDatabase() const
{
return database;
}
void setDatabase(Database* val);
Attachment* getAttachment()
{
return attachment;
}
const Attachment* getAttachment() const
{
return attachment;
}
void setAttachment(Attachment* val);
jrd_tra* getTransaction()
{
return transaction;
}
const jrd_tra* getTransaction() const
{
return transaction;
}
void setTransaction(jrd_tra* val);
Request* getRequest()
{
return request;
}
const Request* getRequest() const
{
return request;
}
void setRequest(Request* val);
SSHORT getCharSet() const;
void markAsSweeper()
{
tdbb_quantum = SWEEP_QUANTUM;
tdbb_flags |= TDBB_sweeper;
}
void bumpStats(const RuntimeStatistics::StatType index, SINT64 delta = 1)
{
reqStat->bumpValue(index, delta);
traStat->bumpValue(index, delta);
attStat->bumpValue(index, delta);
dbbStat->bumpValue(index, delta);
}
void bumpRelStats(const RuntimeStatistics::StatType index, SLONG relation_id, SINT64 delta = 1)
{
// We don't bump counters for dbbStat here, they're merged from attStats on demand
reqStat->bumpValue(index, delta);
traStat->bumpValue(index, delta);
attStat->bumpValue(index, delta);
const RuntimeStatistics* const dummyStat = RuntimeStatistics::getDummy();
// We expect that at least attStat is present (not a dummy object)
fb_assert(attStat != dummyStat);
// Relation statistics is a quite complex beast, so a conditional check
// does not hurt. It also allows to avoid races while accessing the static
// dummy object concurrently.
if (reqStat != dummyStat)
reqStat->bumpRelValue(index, relation_id, delta);
if (traStat != dummyStat)
traStat->bumpRelValue(index, relation_id, delta);
if (attStat != dummyStat)
attStat->bumpRelValue(index, relation_id, delta);
}
ISC_STATUS getCancelState(ISC_STATUS* secondary = NULL);
void checkCancelState();
void reschedule();
const TimeoutTimer* getTimeoutTimer() const
{
return tdbb_reqTimer;
}
// Returns minimum of passed wait timeout and time to expiration of reqTimer.
// Timer value is rounded to the upper whole second.
ULONG adjustWait(ULONG wait) const;
void registerBdb(BufferDesc* bdb)
{
if (tdbb_bdbs.isEmpty()) {
tdbb_flags &= ~TDBB_cache_unwound;
}
fb_assert(!(tdbb_flags & TDBB_cache_unwound));
FB_SIZE_T pos;
if (tdbb_bdbs.find(NULL, pos))
tdbb_bdbs[pos] = bdb;
else
tdbb_bdbs.add(bdb);
}
bool clearBdb(BufferDesc* bdb)
{
if (tdbb_bdbs.isEmpty())
{
// hvlad: the only legal case when thread holds no latches but someone
// tried to release latch is when CCH_unwind was called (and released
// all latches) but caller is unaware about it. See CORE-3034, for example.
// Else it is bug and should be BUGCHECK'ed.
if (tdbb_flags & TDBB_cache_unwound)
return false;
}
fb_assert(!(tdbb_flags & TDBB_cache_unwound));
FB_SIZE_T pos;
if (!tdbb_bdbs.find(bdb, pos))
BUGCHECK(300); // can't find shared latch
tdbb_bdbs[pos] = NULL;
if (pos == tdbb_bdbs.getCount() - 1)
{
while (true)
{
if (tdbb_bdbs[pos] != NULL)
{
tdbb_bdbs.shrink(pos + 1);
break;
}
if (pos == 0)
{
tdbb_bdbs.shrink(0);
break;
}
--pos;
}
}
return true;
}
void resetStack()
{
if (tdbb_flags & TDBB_reset_stack)
{
tdbb_flags &= ~TDBB_reset_stack;
#ifdef WIN_NT
_resetstkoflw();
#endif
}
}
class TimerGuard
{
public:
TimerGuard(thread_db* tdbb, TimeoutTimer* timer, bool autoStop)
: m_tdbb(tdbb),
m_autoStop(autoStop && timer),
m_saveTimer(tdbb->tdbb_reqTimer)
{
m_tdbb->tdbb_reqTimer = timer;
if (timer && timer->expired())
m_tdbb->tdbb_quantum = 0;
}
~TimerGuard()
{
if (m_autoStop)
m_tdbb->tdbb_reqTimer->stop();
m_tdbb->tdbb_reqTimer = m_saveTimer;
}
private:
thread_db* m_tdbb;
bool m_autoStop;
Firebird::RefPtr<TimeoutTimer> m_saveTimer;
};
private:
Firebird::RefPtr<TimeoutTimer> tdbb_reqTimer;
};
class ThreadContextHolder
{
public:
explicit ThreadContextHolder(Firebird::CheckStatusWrapper* status = NULL)
: context(status ? status : &localStatus)
{
context.putSpecific();
if (!cds::threading::Manager::isThreadAttached())
cds::threading::Manager::attachThread();
}
ThreadContextHolder(Database* dbb, Jrd::Attachment* att, FbStatusVector* status = NULL)
: context(status ? status : &localStatus)
{
context.putSpecific();
context.setDatabase(dbb);
context.setAttachment(att);
if (!cds::threading::Manager::isThreadAttached())
cds::threading::Manager::attachThread();
}
~ThreadContextHolder()
{
Firebird::ThreadData::restoreSpecific();
}
thread_db* operator->()
{
return &context;
}
operator thread_db*()
{
return &context;
}
private:
// copying is prohibited
ThreadContextHolder(const ThreadContextHolder&);
ThreadContextHolder& operator= (const ThreadContextHolder&);
Firebird::FbLocalStatus localStatus;
thread_db context;
};
// Helper class to temporarily activate sweeper context
class ThreadSweepGuard
{
@ -776,6 +335,8 @@ inline void SET_DBB(Jrd::Database*& dbb)
// global variables for engine
namespace Jrd {
void suspend();
typedef Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool> ContextPoolHolder;
class DatabaseContextHolder : public Jrd::ContextPoolHolder

View File

@ -1590,203 +1590,3 @@ Lock* Lock::detach()
return next;
}
/**************************************
*
* Someone is trying to drop an object. If there
* are outstanding interests in the existence of
* that object then just mark as blocking and return.
* and release the existence lock.
*
**************************************/
void ExistenceLock::blockingAst()
{
AsyncContextHolder tdbb(lck->lck_dbb, FB_FUNCTION);
MutexLockGuard g(mutex, FB_FUNCTION);
unsigned fl = (flags |= unlocking);
if ((fl & countMask) == 0)
internalUnlock(tdbb, fl, fl & locked);
else
{
flags |= blocking;
flags &= ~unlocking;
}
}
void ExistenceLock::enter245(thread_db* tdbb)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
unsigned fl = flags;
fb_assert((fl & sharedMask) > 0);
if (!(fl & locked))
{
LCK_lock(tdbb, lck, LCK_SR, LCK_WAIT);
if (object)
{
Arg::StatusVector v;
if (!object->checkObject(tdbb, v))
{
LCK_release(tdbb, lck);
ERR_post(v);
}
}
flags |= locked;
}
}
void ExistenceLock::leave245(thread_db* tdbb, bool force)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
unsigned fl = (flags |= unlocking);
fb_assert(fl & locked);
if ((((fl & countMask) == 0) && (fl & blocking)) | force)
internalUnlock(tdbb, fl);
else
flags &= ~unlocking;
}
bool ExistenceLock::exclLock(thread_db* tdbb)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
unsigned fl = (flags += exclusive);
if ((fl & countMask) != exclusive)
{
flags -= exclusive;
printf("false1\n");
return false;
}
auto lckFunction = fl & locked ? LCK_convert : LCK_lock;
if (!lckFunction(tdbb, lck, LCK_EX, getLockWait(tdbb)))
{
flags -= exclusive;
printf("false2\n");
return false;
}
return true;
}
SSHORT ExistenceLock::getLockWait(thread_db* tdbb)
{
jrd_tra* transaction = tdbb->getTransaction();
return transaction ? transaction->getLockWait() : 0;
}
#ifdef DEV_BUILD
bool ExistenceLock::hasExclLock(thread_db*)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
return (flags & exclMask) == exclusive;
}
#endif
void ExistenceLock::unlock(thread_db* tdbb)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
fb_assert(hasExclLock(tdbb));
unsigned fl = flags;
unsigned newFlags;
do
{
newFlags = (fl | unlocking) - exclusive;
} while (!flags.compare_exchange_weak(fl, newFlags, std::memory_order_release, std::memory_order_acquire));
fb_assert((fl & exclMask) == 0);
if ((fl & locked) && !(fl & blocking))
{
LCK_convert(tdbb, lck, LCK_SR, getLockWait(tdbb)); // always succeeds
flags &= ~unlocking;
}
else
internalUnlock(tdbb, fl);
}
void ExistenceLock::internalUnlock(thread_db* tdbb, unsigned fl, bool flLockRelease)
{
fb_assert(mutex.locked());
fb_assert((fl & countMask) == 0);
if (flLockRelease)
{
LCK_release(tdbb, lck); // repost ??????????????
internalObjectDelete(tdbb, fl);
}
else
fb_assert(!(fl & inCache));
flags &= ~(blocking | unlocking | locked);
}
void ExistenceLock::internalObjectDelete(thread_db* tdbb, unsigned fl)
{
if (object)
{
object->afterUnlock(tdbb, fl);
if (!(fl & inCache))
object->retire();
}
}
void ExistenceLock::incrementError [[noreturn]] ()
{
const char* objTypeName = "unknown object";
switch(lck->lck_type)
{
case LCK_rel_exist:
objTypeName = "relation";
break;
case LCK_idx_exist:
objTypeName = "index";
break;
case LCK_prc_exist:
objTypeName = "procedure";
break;
case LCK_tt_exist:
objTypeName = "collation";
break;
case LCK_fun_exist:
objTypeName = "function";
break;
default:
fb_assert(false);
break;
}
fatal_exception::raiseFmt("Can not use %s %s which is going to be dropped in regular request",
objTypeName, object->c_name());
}
void ExistenceLock::releaseLock(thread_db* tdbb, ReleaseMethod rm)
{
Firebird::MutexLockGuard g(mutex, FB_FUNCTION);
switch (rm)
{
case ReleaseMethod::Normal:
if ((flags |= blocking) & locked)
leave245(tdbb);
else if (hasExclLock(tdbb))
unlock(tdbb);
else
fb_assert(false);
break;
case ReleaseMethod::DropObject:
fb_assert(hasExclLock(tdbb));
// fall through
case ReleaseMethod::CloseCache:
LCK_release(tdbb, lck);
internalObjectDelete(tdbb, flags);
break;
}
}

View File

@ -196,134 +196,6 @@ void LCK_write_data(Jrd::thread_db*, Jrd::Lock*, LOCK_DATA_T);
namespace Jrd {
// fb_assert(tdbb->getDatabase()->dbb_mdc->mdc_use_mutex.locked());
// fb_assert(!tdbb->getAttachment()->isSystem());
class ExistenceLock
{
public:
ExistenceLock(MemoryPool& p, thread_db* tdbb, lck_t type, SLONG key, CacheObject* obj)
: lck(FB_NEW_RPT(p, 0) Lock(tdbb, sizeof(SLONG), type, this, ast)),
flags(inCache),
object(obj)
{
lck->setKey(key);
}
enum class ReleaseMethod {Normal, DropObject, CloseCache};
Resource::State inc(thread_db* tdbb)
{
unsigned fl = ++flags;
fb_assert(!(fl & countChk));
if (fl & exclMask)
{
--flags;
incrementError();
}
if (fl & countMask)
printf("inc1\n");
return (fl & locked) && !(fl & unlocking) ? Resource::State::Locked : Resource::State::Counted;
}
// make sure we have SH existence lock
void enter245(thread_db* tdbb);
Resource::State dec(thread_db* tdbb)
{
unsigned fl = --flags;
fb_assert(!(fl & countChk));
//fb_assert(((fl + 1) & count) > 0);
return ((fl & countMask) == 0) && (fl & blocking) ? Resource::State::Unlocking : Resource::State::Posted;
}
// release shared lock if needed (or unconditionally when forced set)
void leave245(thread_db* tdbb, bool force = false);
unsigned getUseCount() const
{
static_assert(sharedMask & 1); // Other cases shift is needed to return use count
return flags & sharedMask;
}
bool exclLock(thread_db* tdbb); // Take exclusive lock
#ifdef DEV_BUILD
bool hasExclLock(thread_db* tdbb); // Is object locked exclusively?
#endif
void unlock(thread_db* tdbb); // Release exclusive lock
void releaseLock(thread_db* tdbb, ReleaseMethod rm); // Release any lock
private:
static int ast(void* self)
{
reinterpret_cast<ExistenceLock*>(self)->blockingAst();
return 0;
}
void blockingAst();
void incrementError [[noreturn]] ();
SSHORT getLockWait(thread_db* tdbb);
void internalUnlock(thread_db* tdbb, unsigned fl, bool flLockRelease = true);
void internalObjectDelete(thread_db* tdbb, unsigned fl);
public:
Firebird::Mutex mutex;
private:
Firebird::AutoPtr<Lock> lck;
std::atomic<unsigned> flags;
CacheObject* object;
public:
static const unsigned sharedMask = 0x000FFFFF;
static const unsigned exclMask = 0x07E00000;
static const unsigned countMask = sharedMask | exclMask;
static const unsigned countChk = 0x00100000;
static const unsigned exclusive = 0x00200000;
static const unsigned exCheck = 0x08000000;
static const unsigned inCache = 0x10000000;
static const unsigned unlocking = 0x20000000;
static const unsigned locked = 0x40000000;
static const unsigned blocking = 0x80000000;
};
class ExistenceGuard
{
public:
ExistenceGuard(thread_db* t, ExistenceLock& l)
: tdbb(t), lck(&l)
{
init();
}
ExistenceGuard(thread_db* t, ExistenceLock* l)
: tdbb(t), lck(l)
{
init();
}
~ExistenceGuard()
{
if (lck && (lck->dec(tdbb) == Resource::State::Unlocking))
lck->leave245(tdbb);
}
private:
thread_db* tdbb;
ExistenceLock* lck;
void init()
{
if (lck && lck->inc(tdbb) != Resource::State::Locked)
lck->enter245(tdbb);
}
};
class AutoLock
{
public:

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,7 @@
#include "../jrd/val.h"
#include "../jrd/irq.h"
#include "../jrd/drq.h"
#include "../jrd/exe.h"
#include "../jrd/CharSetContainer.h"
@ -85,60 +86,6 @@ public:
const int TFB_computed = 1;
const int TFB_array = 2;
const int TRIGGER_PRE_STORE = 1;
const int TRIGGER_POST_STORE = 2;
const int TRIGGER_PRE_MODIFY = 3;
const int TRIGGER_POST_MODIFY = 4;
const int TRIGGER_PRE_ERASE = 5;
const int TRIGGER_POST_ERASE = 6;
const int TRIGGER_MAX = 7;
// trigger type prefixes
const int TRIGGER_PRE = 0;
const int TRIGGER_POST = 1;
// trigger type suffixes
const int TRIGGER_STORE = 1;
const int TRIGGER_MODIFY = 2;
const int TRIGGER_ERASE = 3;
// that's how trigger action types are encoded
/*
bit 0 = TRIGGER_PRE/TRIGGER_POST flag,
bits 1-2 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #1),
bits 3-4 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #2),
bits 5-6 = TRIGGER_STORE/TRIGGER_MODIFY/TRIGGER_ERASE (slot #3),
and finally the above calculated value is decremented
example #1:
TRIGGER_POST_ERASE =
= ((TRIGGER_ERASE << 1) | TRIGGER_POST) - 1 =
= ((3 << 1) | 1) - 1 =
= 0x00000110 (6)
example #2:
TRIGGER_PRE_STORE_MODIFY =
= ((TRIGGER_MODIFY << 3) | (TRIGGER_STORE << 1) | TRIGGER_PRE) - 1 =
= ((2 << 3) | (1 << 1) | 0) - 1 =
= 0x00010001 (17)
example #3:
TRIGGER_POST_MODIFY_ERASE_STORE =
= ((TRIGGER_STORE << 5) | (TRIGGER_ERASE << 3) | (TRIGGER_MODIFY << 1) | TRIGGER_POST) - 1 =
= ((1 << 5) | (3 << 3) | (2 << 1) | 1) - 1 =
= 0x00111100 (60)
*/
// that's how trigger types are decoded
#define TRIGGER_ACTION(value, shift) \
(((((value + 1) >> shift) & 3) << 1) | ((value + 1) & 1)) - 1
#define TRIGGER_ACTION_SLOT(value, slot) \
TRIGGER_ACTION(value, (slot * 2 - 1) )
const int TRIGGER_COMBINED_MAX = 128;
#include "../jrd/exe_proto.h"
#include "../jrd/obj.h"
#include "../dsql/sym.h"
@ -159,8 +106,9 @@ public:
private:
const ExtEngineManager::Procedure* prc_external;
jrd_prc(MemoryPool& p, MetaId id)
: Routine(p, id),
public:
explicit jrd_prc(RoutinePermanent* perm)
: Routine(perm),
prc_record_format(NULL),
prc_type(prc_legacy),
prc_external(NULL)
@ -168,26 +116,17 @@ private:
}
public:
explicit jrd_prc(MemoryPool& p)
: Routine(p),
prc_record_format(NULL),
prc_type(prc_legacy),
prc_external(NULL)
{
}
public:
virtual int getObjectType() const
int getObjectType() const override
{
return obj_procedure;
}
virtual SLONG getSclType() const
SLONG getSclType() const override
{
return obj_procedures;
}
virtual void releaseFormat()
void releaseFormat() override
{
delete prc_record_format;
prc_record_format = NULL;
@ -199,19 +138,22 @@ private:
delete prc_external;
}
static int blockingAst(void* ast_object);
public:
static jrd_prc* create(thread_db* tdbb, MetaId id, CacheObject::Flag flags);
static jrd_prc* create(thread_db* tdbb, MemoryPool& p, MetaId id, CacheObject::Flag flags);
static Lock* getLock(MemoryPool& p, thread_db* tdbb);
virtual bool checkCache(thread_db* tdbb) const;
bool checkCache(thread_db* tdbb) const override;
virtual void releaseExternal()
void releaseExternal() override
{
delete prc_external;
prc_external = NULL;
}
protected:
virtual bool reload(thread_db* tdbb); // impl is in met.epp
bool reload(thread_db* tdbb) override; // impl is in met.epp
};
@ -257,681 +199,16 @@ enum IndexStatus
class CharSet;
class ObjectBase : public HazardObject
{
public:
enum ResetType {Recompile, Mark, Commit, Rollback};
typedef SLONG ReturnedId; // enable '-1' as not found
public:
virtual void resetDependentObject(thread_db* tdbb, ResetType rt) = 0;
virtual void eraseObject(thread_db* tdbb) = 0; // erase object
public:
void resetDependentObjects(thread_db* tdbb, TraNumber olderThan);
void addDependentObject(thread_db* tdbb, ObjectBase* dep);
void removeDependentObject(thread_db* tdbb, ObjectBase* dep);
[[noreturn]] void busyError(thread_db* tdbb, MetaId id, const char* name);
};
namespace CacheFlag
{
static const CacheObject::Flag COMMITTED = 0x01;
static const CacheObject::Flag ERASED = 0x02;
static const CacheObject::Flag NOSCAN = 0x04;
static const CacheObject::Flag AUTOCREATE = 0x08;
static const CacheObject::Flag IGNORE_MASK = COMMITTED | ERASED;
}
template <class OBJ>
class CacheList : public HazardObject
{
public:
CacheList(OBJ* obj, TraNumber currentTrans, CacheObject::Flag fl = 0)
: object(obj), next(nullptr), traNumber(currentTrans), cacheFlags(fl)
{ }
// find appropriate object in cache
OBJ* getObject(TraNumber currentTrans, CacheObject::Flag flags) const
{
CacheObject::Flag f(cacheFlags.load() & ~(flags & CacheFlag::IGNORE_MASK));
// object deleted, good bye
if (f & CacheFlag::ERASED)
return nullptr;
// committed (i.e. confirmed) objects are freely available
if (f & CacheFlag::COMMITTED)
return object;
// transaction that created an object can always access it
if ((traNumber == currentTrans) && currentTrans)
return object;
// try next level
CacheList* n = next.load(atomics::memory_order_acquire);
return n ? n->getObject(currentTrans, flags) : nullptr;
}
bool isBusy(TraNumber currentTrans) const
{
return traNumber != currentTrans && !(cacheFlags & CacheFlag::COMMITTED);
}
// add new entry to the list
static bool add(atomics::atomic<CacheList*>& list, CacheList* newVal)
{
HazardPtr<CacheList> oldVal(list);
do
{
if (oldVal && oldVal->isBusy(newVal->traNumber)) // modified in other transaction
return false;
newVal->next.store(oldVal.getPointer(), atomics::memory_order_relaxed);
} while (! oldVal.replace2(list, newVal));
return true;
}
// remove too old objects - they are anyway can't be in use
static TraNumber cleanup(atomics::atomic<CacheList*>& list, const TraNumber oldest)
{
TraNumber rc = 0;
for (HazardPtr<CacheList> entry(list); entry; entry.set(entry->next))
{
if ((entry->cacheFlags & CacheFlag::COMMITTED) && entry->traNumber < oldest)
{
if (entry->cacheFlags.fetch_or(CacheFlag::ERASED) & CacheFlag::ERASED)
break; // someone else also performs cleanup
// split remaining list off
if (entry.replace2(list, nullptr))
{
while (entry && !(entry->cacheFlags.fetch_or(CacheFlag::ERASED) & CacheFlag::ERASED))
{
entry->retire();
OBJ::destroy(entry->object);
entry.set(entry->next);
}
}
break;
}
// store traNumber of last not removed list element
rc = entry->traNumber;
}
return rc; // 0 is returned in a case when list becomes empty
}
// created earlier object is OK and should become visible to the world
void commit(TraNumber currentTrans, TraNumber nextTrans)
{
fb_assert(cacheFlags == 0);
fb_assert(traNumber == currentTrans);
traNumber = nextTrans;
cacheFlags |= CacheFlag::COMMITTED;
}
// created earlier object is bad and should be destroyed
static void rollback(atomics::atomic<CacheList*>& list, const TraNumber currentTran)
{
// Take into an account that no other transaction except current (i.e. object creator)
// can access uncommitted objects, only list entries may be accessed as hazard pointers.
// Therefore rollback can retire such entries at once, a kind of pop() from stack.
HazardPtr<CacheList> entry(list);
while (entry)
{
if (entry->cacheFlags & CacheFlag::COMMITTED)
break;
fb_assert(entry->traNumber == currentTran);
if (entry.replace2(list, entry->next))
{
entry->retire();
OBJ::destroy(entry->object);
entry = list;
}
}
}
// mark as erased
void erase()
{
cacheFlags |= CacheFlag::ERASED;
}
void assertCommitted()
{
fb_assert(cacheFlags & CacheFlag::COMMITTED);
}
private:
OBJ* object;
atomics::atomic<CacheList*> next;
TraNumber traNumber; // when COMMITTED not set - stores transaction that created this list element
// when COMMITTED is set - stores transaction after which older elements are not needed
// traNumber to be changed BEFORE setting COMMITTED
MdcVersion version; // version of metadata cache when object was added
atomics::atomic<CacheObject::Flag> cacheFlags;
};
class CurrentTransaction
{
public:
static TraNumber getNumber(thread_db* tdbb);
/* static TraNumber currentTraNumber(thread_db* tdbb)
{
jrd_tra* tra = tdbb->getTransaction();
return tra ? tra->tra_number : 0;
} */
};
template <class OBJ>
class CacheElement : public ObjectBase
{
typedef CacheList<OBJ> CachedObj;
public:
CacheElement(MetaId id) :
list(nullptr), resetAt(0), myId(id)
{ }
~CacheElement()
{
cleanup();
}
OBJ* getObject(thread_db* tdbb, CacheObject::Flag flags = 0)
{
HazardPtr<CachedObj> l(list);
if (!l)
return nullptr;
return l->getObject(CurrentTransaction::getNumber(tdbb), flags);
}
bool storeObject(thread_db* tdbb, OBJ* obj, CacheObject::Flag fl = 0)
{
TraNumber oldest = tdbb->getDatabase()->dbb_oldest_active;
TraNumber oldResetAt = resetAt.load(atomics::memory_order_acquire);
if (oldResetAt && oldResetAt < oldest)
setNewResetAt(oldResetAt, CachedObj::cleanup(list, oldest));
TraNumber current = CurrentTransaction::getNumber(tdbb);
CachedObj* value = FB_NEW CachedObj(obj, current, fl & CacheFlag::IGNORE_MASK);
if (!CachedObj::add(list, value))
{
delete value;
return false;
}
setNewResetAt(oldResetAt, current);
return true;
}
void commit(thread_db* tdbb)
{
HazardPtr<CachedObj> current(list);
if (current)
current->commit(CurrentTransaction::getNumber(tdbb), tdbb->getDatabase()->dbb_next_transaction);
}
void rollback(thread_db* tdbb)
{
CacheList<OBJ>::rollback(list, CurrentTransaction::getNumber(tdbb));
}
void cleanup()
{
list.load()->assertCommitted();
CacheList<OBJ>::cleanup(list, MAX_TRA_NUMBER);
}
void resetDependentObject(thread_db* tdbb, ResetType rt) override
{
switch (rt)
{
case ObjectBase::ResetType::Recompile:
{
OBJ* newObj = OBJ::create(tdbb, myId, 0);
if (!storeObject(tdbb, newObj))
{
OBJ::destroy(newObj);
OBJ* oldObj = getObject(tdbb);
busyError(tdbb, myId, oldObj ? oldObj->c_name() : nullptr);
}
}
break;
case ObjectBase::ResetType::Mark:
// used in AST, therefore ignore error when saving empty object
if (storeObject(tdbb, nullptr))
commit(tdbb);
break;
case ObjectBase::ResetType::Commit:
commit(tdbb);
break;
case ObjectBase::ResetType::Rollback:
rollback(tdbb);
break;
}
}
void eraseObject(thread_db* tdbb) override
{
HazardPtr<CachedObj> l(list);
fb_assert(l);
if (!l)
return;
if (!storeObject(tdbb, nullptr, CacheFlag::ERASED))
{
OBJ* oldObj = getObject(tdbb);
busyError(tdbb, myId, oldObj ? oldObj->c_name() : nullptr);
}
}
private:
void setNewResetAt(TraNumber oldVal, TraNumber newVal)
{
resetAt.compare_exchange_strong(oldVal, newVal,
atomics::memory_order_release, atomics::memory_order_relaxed);
}
atomics::atomic<CachedObj*> list;
atomics::atomic<TraNumber> resetAt;
MetaId myId;
};
template <class E, unsigned SUBARRAY_SHIFT = 8>
class CacheVector : public Firebird::PermanentStorage
{
public:
static const unsigned SUBARRAY_SIZE = 1 << SUBARRAY_SHIFT;
static const unsigned SUBARRAY_MASK = SUBARRAY_SIZE - 1;
typedef CacheElement<E> StoredObject;
typedef atomics::atomic<StoredObject*> SubArrayData;
typedef atomics::atomic<SubArrayData*> ArrayData;
typedef SharedReadVector<ArrayData, 4> Storage;
explicit CacheVector(MemoryPool& pool)
: Firebird::PermanentStorage(pool),
m_objects(getPool())
{}
private:
static FB_SIZE_T getCount(const HazardPtr<typename Storage::Generation>& v)
{
return v->getCount() << SUBARRAY_SHIFT;
}
SubArrayData* getDataPointer(MetaId id) const
{
auto up = m_objects.readAccessor();
if (id >= getCount(up))
return nullptr;
auto sub = up->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
return &sub[id & SUBARRAY_MASK];
}
void grow(FB_SIZE_T reqSize)
{
fb_assert(reqSize > 0);
reqSize = ((reqSize - 1) >> SUBARRAY_SHIFT) + 1;
Firebird::MutexLockGuard g(objectsGrowMutex, FB_FUNCTION);
m_objects.grow(reqSize);
auto wa = m_objects.writeAccessor();
fb_assert(wa->getCapacity() >= reqSize);
while (wa->getCount() < reqSize)
{
SubArrayData* sub = FB_NEW_POOL(getPool()) SubArrayData[SUBARRAY_SIZE];
memset(sub, 0, sizeof(SubArrayData) * SUBARRAY_SIZE);
wa->add()->store(sub, atomics::memory_order_release);
}
}
public:
StoredObject* getData(thread_db*, MetaId id)
{
auto ptr = getDataPointer(id);
return ptr ? *ptr : nullptr;
}
E* getObject(thread_db* tdbb, MetaId id, CacheObject::Flag flags)
{
// In theory that should be endless cycle - object may arrive/disappear again and again.
// But in order to faster find devel problems we run it very limited number of times.
#ifdef DEV_BUILD
for (int i = 0; i < 2; ++i)
#else
for (;;)
#endif
{
auto ptr = getDataPointer(id);
if (ptr)
{
HazardPtr<StoredObject> data(*ptr);
if (data)
{
auto rc = data->getObject(tdbb, flags);
if (rc)
return rc;
}
}
if (!(flags & CacheFlag::AUTOCREATE))
return nullptr;
auto val = E::create(tdbb, id, flags);
if (!val)
(Firebird::Arg::Gds(isc_random) << "Object create failed").raise();
if (storeObject(tdbb, id, val))
return val;
E::destroy(val);
}
#ifdef DEV_BUILD
(Firebird::Arg::Gds(isc_random) << "Object suddenly disappeared").raise();
#endif
}
StoredObject* storeObject(thread_db* tdbb, MetaId id, E* const val)
{
if (id >= getCount())
grow(id + 1);
auto ptr = getDataPointer(id);
fb_assert(ptr);
HazardPtr<StoredObject> data(*ptr);
if (!data)
{
MemoryPool* pool = tdbb->getDatabase()->dbb_permanent;
fb_assert(pool);
StoredObject* newData = FB_NEW_POOL(*pool) StoredObject(id);
if (!data.replace2(*ptr, newData))
delete newData;
else
data.set(*ptr);
}
if (!data->storeObject(tdbb, val))
data.clear();
return data.getPointer();
}
StoredObject* lookup(thread_db* tdbb, std::function<bool(E* val)> cmp, MetaId* foundId = nullptr) const
{
auto a = m_objects.readAccessor();
for (FB_SIZE_T i = 0; i < a->getCount(); ++i)
{
SubArrayData* const sub = a->value(i).load(atomics::memory_order_relaxed);
if (!sub)
continue;
for (SubArrayData* end = &sub[SUBARRAY_SIZE]; sub < end--;)
{
StoredObject* ptr = end->load(atomics::memory_order_relaxed);
if (!ptr)
continue;
E* val = ptr->getObject(tdbb);
if (val && cmp(val))
{
if (foundId)
*foundId = (i << SUBARRAY_SHIFT) + (end - sub);
return ptr;
}
}
}
return nullptr;
}
~CacheVector()
{
auto a = m_objects.writeAccessor();
for (FB_SIZE_T i = 0; i < a->getCount(); ++i)
{
SubArrayData* const sub = a->value(i).load(atomics::memory_order_relaxed);
if (!sub)
continue;
for (SubArrayData* end = &sub[SUBARRAY_SIZE]; sub < end--;)
delete *end; // no need using release here in CacheVector's dtor
delete[] sub;
}
delete a;
}
FB_SIZE_T getCount() const
{
return m_objects.readAccessor()->getCount() << SUBARRAY_SHIFT;
}
bool replace2(MetaId id, HazardPtr<E>& oldVal, E* const newVal)
{
if (id >= getCount())
grow(id + 1);
auto a = m_objects.readAccessor();
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
sub = &sub[id & SUBARRAY_MASK];
return oldVal.replace2(sub, newVal);
}
bool clear(MetaId id)
{
if (id >= getCount())
return false;
auto a = m_objects.readAccessor();
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
fb_assert(sub);
sub = &sub[id & SUBARRAY_MASK];
sub->store(nullptr, atomics::memory_order_release);
return true;
}
bool load(MetaId id, HazardPtr<E>& val) const
{
auto a = m_objects.readAccessor();
if (id < getCount(a))
{
SubArrayData* sub = a->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
if (sub)
{
val.set(sub[id & SUBARRAY_MASK]);
if (val && val->hasData())
return true;
}
}
return false;
}
HazardPtr<E> load(MetaId id) const
{
HazardPtr<E> val;
if (!load(id, val))
val.clear();
return val;
}
HazardPtr<typename Storage::Generation> readAccessor() const
{
return m_objects.readAccessor();
}
class Snapshot;
class Iterator
{
public:
HazardPtr<E> operator*()
{
return get();
}
HazardPtr<E> operator->()
{
return get();
}
Iterator& operator++()
{
index = snap->locateData(index + 1);
return *this;
}
bool operator==(const Iterator& itr) const
{
fb_assert(snap == itr.snap);
return index == itr.index;
}
bool operator!=(const Iterator& itr) const
{
fb_assert(snap == itr.snap);
return index != itr.index;
}
private:
void* operator new(size_t);
void* operator new[](size_t);
public:
enum class Location {Begin, End};
Iterator(const Snapshot* s, Location loc)
: snap(s),
index(loc == Location::Begin ? snap->locateData(0) :
snap->data->getCount() << SUBARRAY_SHIFT)
{ }
HazardPtr<E> get()
{
HazardPtr<E> rc;
if (!snap->load(index, rc))
rc.clear();
return rc;
}
private:
const Snapshot* snap;
FB_SIZE_T index;
};
class Snapshot
{
private:
void* operator new(size_t);
void* operator new[](size_t);
public:
Snapshot(const CacheVector* array)
: data(array->readAccessor())
{ }
Iterator begin() const
{
return Iterator(this, Iterator::Location::Begin);
}
Iterator end() const
{
return Iterator(this, Iterator::Location::End);
}
FB_SIZE_T locateData(FB_SIZE_T index) const
{
for (FB_SIZE_T i = index >> SUBARRAY_SHIFT; i < data->getCount(); ++i, index = 0)
{
SubArrayData* const sub = data->value(i).load(atomics::memory_order_acquire);
if (!sub)
continue;
for (FB_SIZE_T j = index & SUBARRAY_MASK; j < SUBARRAY_SIZE; ++j)
{
auto p = sub[j].load(atomics::memory_order_acquire);
if (p && p->hasData())
return (i << SUBARRAY_SHIFT) + j;
}
}
return data->getCount() << SUBARRAY_SHIFT;
}
bool load(MetaId id, HazardPtr<E>& val) const
{
if (id < (data->getCount() << SUBARRAY_SHIFT))
{
SubArrayData* sub = data->value(id >> SUBARRAY_SHIFT).load(atomics::memory_order_acquire);
if (sub)
{
val.set(sub[id & SUBARRAY_MASK]);
if (val && val->hasData())
return true;
}
}
return false;
}
HazardPtr<typename Storage::Generation> data;
};
Snapshot snapshot() const
{
return Snapshot(this);
}
private:
Storage m_objects;
Firebird::Mutex objectsGrowMutex;
};
typedef CacheElement<DbTriggers, NullClass> TriggersSet;
class MetadataCache : public Firebird::PermanentStorage
{
friend class CharSetContainer;
/*
class ListNodeAllocator
{
public:
typedef int value_type;
T* allocate(std::size_t n);
void deallocate(T* p, std::size_t n);
};
struct MetaTraits : public cds::container::michael_list::traits
{
typedef ListNodeAllocator allocator;
};
template <typename C>
using MetaList = cds::container::MichaelList<cds::gc::DHP, C, MetaTraits>;
*/
public:
typedef CacheVector<CharSetVers, CharSetContainer> Charsets; // intl character set descriptions
typedef Charsets::StoredObject Charset; // character set stored in cache vector
MetadataCache(MemoryPool& pool)
: Firebird::PermanentStorage(pool),
mdc_relations(getPool()),
@ -939,17 +216,14 @@ public:
mdc_functions(getPool()),
mdc_charsets(getPool()),
mdc_charset_ids(getPool())
{
memset(mdc_triggers, 0, sizeof(mdc_triggers));
mdc_ddl_triggers = nullptr;
}
{ }
~MetadataCache();
/*
// Objects are placed to this list after DROP OBJECT
// and wait for current OAT >= NEXT when DDL committed
atomics::atomic<CacheList<ObjectBase>*> dropList;
atomics::atomic<Cache List<ObjectBase>*> dropList;
{
public:
void drop(
@ -969,7 +243,7 @@ public:
jrd_rel* getRelation(thread_db* tdbb, ULONG rel_id);
void setRelation(thread_db* tdbb, ULONG rel_id, jrd_rel* rel);
void releaseTrigger(thread_db* tdbb, USHORT triggerId, const MetaName& name);
TrigVectorPtr* getTriggers(USHORT triggerId);
const Triggers* getTriggers(USHORT tType);
MetaId relCount()
{
@ -1002,18 +276,8 @@ public:
return mdc_procedures.storeObject(tdbb, id, p);
}
CharSetContainer* getCharSet(thread_db* tdbb, MetaId id)
{
if (id >= mdc_charsets.getCount())
return nullptr;
return mdc_charsets.getObject(tdbb, id, 0);
}
bool makeCharSet(thread_db* tdbb, MetaId id, CharSetContainer* cs)
{
return mdc_charsets.storeObject(tdbb, id, cs);
}
CharSetContainer* getCharSet(thread_db* tdbb, MetaId id);
bool makeCharSet(thread_db* tdbb, MetaId id, CharSetContainer* cs);
// former met_proto.h
#ifdef DEV_BUILD
@ -1023,17 +287,19 @@ public:
#endif
static void clear_cache(thread_db* tdbb);
static void update_partners(thread_db* tdbb);
static bool routine_in_use(thread_db* tdbb, HazardPtr<Routine> routine);
void load_db_triggers(thread_db* tdbb, int type);
void load_ddl_triggers(thread_db* tdbb);
void load_db_triggers(thread_db* tdbb, int type, bool force = false);
void load_ddl_triggers(thread_db* tdbb, bool force = false);
static jrd_prc* lookup_procedure(thread_db* tdbb, const QualifiedName& name, bool noscan);
static jrd_prc* lookup_procedure_id(thread_db* tdbb, MetaId id, bool return_deleted, bool noscan, USHORT flags);
static CacheElement<jrd_prc>* lookupProcedure(thread_db* tdbb, const MetaName& name);
static CacheElement<jrd_prc>* lookupProcedure(thread_db* tdbb, MetaId id, bool noscan = false);
static CacheElement<jrd_prc, RoutinePermanent>* lookupProcedure(thread_db* tdbb, const QualifiedName& name);
static CacheElement<jrd_prc, RoutinePermanent>* lookupProcedure(thread_db* tdbb, MetaId id, bool noscan = false);
static CacheElement<jrd_prc, RoutinePermanent>* lookupFunction(thread_db* tdbb, const QualifiedName& name);
static CacheElement<jrd_prc, RoutinePermanent>* lookupFunction(thread_db* tdbb, MetaId id, bool noscan = false);
static jrd_rel* lookup_relation(thread_db*, const MetaName&);
static jrd_rel* lookup_relation_id(thread_db*, MetaId, bool);
static CacheElement<jrd_rel>* lookupRelation(thread_db* tdbb, const MetaName& name);
static CacheElement<jrd_rel>* lookupRelation(thread_db* tdbb, MetaId id, bool noscan = false);
static jrd_rel* lookup_relation_id(thread_db*, MetaId, bool noscan = false);
static CachedRelation* lookupRelation(thread_db* tdbb, const MetaName& name);
static CachedRelation* lookupRelation(thread_db* tdbb, MetaId id, bool noscan = false);
CachedRelation* lookupRelation(MetaId id);
static void lookup_index(thread_db* tdbb, MetaName& index_name, const MetaName& relation_name, USHORT number);
static ObjectBase::ReturnedId lookup_index_name(thread_db* tdbb, const MetaName& index_name,
MetaId* relation_id, IndexStatus* status);
@ -1049,18 +315,32 @@ public:
// end of met_proto.h
static bool checkRelation(thread_db* tdbb, jrd_rel* relation);
static Charset* lookupCharset(thread_db* tdbb, USHORT tt_id);
MdcVersion getVersion()
{
return mdc_version.load(std::memory_order_relaxed);
}
MdcVersion nextVersion()
{
return ++mdc_version;
}
private:
CacheVector<jrd_rel> mdc_relations;
CacheVector<jrd_prc> mdc_procedures;
TrigVectorPtr mdc_triggers[DB_TRIGGER_MAX];
TrigVectorPtr mdc_ddl_triggers;
CacheVector<Function> mdc_functions; // User defined functions
CacheVector<CharSetContainer> mdc_charsets; // intl character set descriptions
CacheVector<jrd_rel, RelationPermanent> mdc_relations;
CacheVector<jrd_prc, RoutinePermanent> mdc_procedures;
TriggersSet mdc_triggers[DB_TRIGGER_MAX];
TriggersSet mdc_ddl_triggers;
CacheVector<Function, RoutinePermanent> mdc_functions; // User defined functions
Charsets mdc_charsets; // intl character set descriptions
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
MetaName, USHORT> > > mdc_charset_ids; // Character set ids
std::atomic<MdcVersion> mdc_version; // Current version of metadata cache
public:
Firebird::Mutex mdc_db_triggers_mutex, // Also used for load DDL triggers
Firebird::Mutex
mdc_charset_mutex; // Protects mdc_charset_ids
};

View File

@ -24,6 +24,7 @@
#ifndef JRD_MET_PROTO_H
#define JRD_MET_PROTO_H
#include "../common/classes/array.h"
#include "../jrd/MetaName.h"
#include "../jrd/HazardPtr.h"
@ -38,6 +39,7 @@ namespace Jrd
class Format;
class jrd_rel;
class CompilerScratch;
struct Dependency;
class DmlNode;
class Database;
struct bid;
@ -47,6 +49,10 @@ namespace Jrd
class DeferredWork;
struct FieldInfo;
class ExceptionItem;
class GeneratorItem;
class BlobFilter;
class Triggers;
}
struct SubtypeInfo
@ -72,7 +78,7 @@ Jrd::Format* MET_current(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_delete_dependencies(Jrd::thread_db*, const Jrd::MetaName&, int, Jrd::jrd_tra*);
void MET_delete_shadow(Jrd::thread_db*, USHORT);
void MET_error(const TEXT*, ...);
Jrd::Format* MET_format(Jrd::thread_db*, Jrd::jrd_rel*, USHORT);
Jrd::Format* MET_format(Jrd::thread_db*, Jrd::RelationPermanent*, USHORT);
bool MET_get_char_coll_subtype_info(Jrd::thread_db*, USHORT, SubtypeInfo* info);
Jrd::DmlNode* MET_get_dependencies(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR*, const ULONG,
Jrd::CompilerScratch*, Jrd::bid*, Jrd::Statement**,
@ -83,7 +89,7 @@ ULONG MET_get_rel_flags_from_TYPE(USHORT);
bool MET_get_repl_state(Jrd::thread_db*, const Jrd::MetaName&);
void MET_get_shadow_files(Jrd::thread_db*, bool);
bool MET_load_exception(Jrd::thread_db*, Jrd::ExceptionItem&);
void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::MetaName&, Jrd::TrigVectorPtr*);
void MET_load_trigger(Jrd::thread_db*, Jrd::jrd_rel*, const Jrd::MetaName&, Jrd::Triggers&);
void MET_lookup_cnstrt_for_index(Jrd::thread_db*, Jrd::MetaName& constraint, const Jrd::MetaName& index_name);
void MET_lookup_cnstrt_for_trigger(Jrd::thread_db*, Jrd::MetaName&, Jrd::MetaName&, const Jrd::MetaName&);
void MET_lookup_exception(Jrd::thread_db*, SLONG, /* OUT */ Jrd::MetaName&, /* OUT */ Firebird::string*);
@ -93,19 +99,20 @@ bool MET_load_generator(Jrd::thread_db*, Jrd::GeneratorItem&, bool* sysGen = 0,
SLONG MET_lookup_generator(Jrd::thread_db*, const Jrd::MetaName&, bool* sysGen = 0, SLONG* step = 0);
bool MET_lookup_generator_id(Jrd::thread_db*, SLONG, Jrd::MetaName&, bool* sysGen = 0);
void MET_update_generator_increment(Jrd::thread_db* tdbb, SLONG gen_id, SLONG step);
void MET_lookup_index_condition(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, Jrd::index_desc* idx);
void MET_lookup_index_expression(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*);
void MET_lookup_index_expression_blr(Jrd::thread_db*, Jrd::MetaName index_name, Jrd::bid& expr_blob_id);
bool MET_lookup_partner(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, Jrd::index_desc* idx, const TEXT* index_name);
Jrd::DmlNode* MET_parse_blob(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::bid*, Jrd::CompilerScratch**,
Jrd::Statement**, bool, bool);
void MET_parse_sys_trigger(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*);
void MET_release_existence(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_release_trigger(Jrd::thread_db*, Jrd::TrigVectorPtr*, const Jrd::MetaName&);
void MET_release_triggers(Jrd::thread_db*, Jrd::TrigVectorPtr*, bool);
void MET_revoke(Jrd::thread_db*, Jrd::jrd_tra*, const Jrd::MetaName&,
const Jrd::MetaName&, const Firebird::string&);
void MET_scan_partners(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_scan_relation(Jrd::thread_db*, Jrd::jrd_rel*&);
void MET_store_dependencies(Jrd::thread_db*, Firebird::Array<Jrd::Dependency>&, Jrd::jrd_rel*,
const Jrd::MetaName&, int, Jrd::jrd_tra*);
void MET_trigger_msg(Jrd::thread_db*, Firebird::string&, const Jrd::MetaName&, USHORT);
void MET_update_shadow(Jrd::thread_db*, Jrd::Shadow*, USHORT);
void MET_update_transaction(Jrd::thread_db*, Jrd::jrd_tra*, const bool);

View File

@ -1022,8 +1022,8 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
fb_assert(tail->csb_relation);
CMP_post_access(tdbb, csb, tail->csb_relation->rel_security_name,
tail->csb_view ? tail->csb_view->rel_id : 0,
SCL_update, obj_relations, tail->csb_relation->rel_name);
tail->csb_view ? tail->csb_view->getId() : 0,
SCL_update, obj_relations, tail->csb_relation->getName());
}
rsb = FB_NEW_POOL(getPool()) LockedStream(csb, rsb, rse->hasSkipLocked());
@ -1076,7 +1076,7 @@ void Optimizer::compileRelation(StreamType stream)
tail->csb_idx = FB_NEW_POOL(getPool()) IndexDescList(getPool(), idxList);
if (tail->csb_plan)
markIndices(tail, relation->rel_id);
markIndices(tail, relation->getId());
}
const auto format = CMP_format(tdbb, csb, stream);
@ -1656,7 +1656,7 @@ void Optimizer::checkIndices()
((idx.idx_runtime_flags & idx_plan_navigate) && !(idx.idx_runtime_flags & idx_navigate)))
{
if (relation)
MetadataCache::lookup_index(tdbb, index_name, relation->rel_name, (USHORT) (idx.idx_id + 1));
MetadataCache::lookup_index(tdbb, index_name, relation->getName(), (USHORT) (idx.idx_id + 1));
else
index_name = "";
@ -2707,7 +2707,7 @@ RecordSource* Optimizer::generateRetrieval(StreamType stream,
else if (relation->isVirtual())
{
// Virtual table: monitoring or security
switch (relation->rel_id)
switch (relation->getId())
{
case rel_global_auth_mapping:
rsb = FB_NEW_POOL(getPool()) GlobalMappingScan(csb, alias, stream, relation);
@ -2948,7 +2948,7 @@ string Optimizer::getStreamName(StreamType stream)
string name;
if (relation)
name = relation->rel_name.c_str();
name = relation->getName().c_str();
else if (procedure)
name = procedure->getName().toString();
@ -2983,7 +2983,7 @@ string Optimizer::makeAlias(StreamType stream)
if (csb_tail->csb_alias)
alias_list.push(*csb_tail->csb_alias);
else if (csb_tail->csb_relation)
alias_list.push(csb_tail->csb_relation->rel_name.c_str());
alias_list.push(csb_tail->csb_relation->getName().c_str());
if (!csb_tail->csb_view)
break;
@ -3000,7 +3000,7 @@ string Optimizer::makeAlias(StreamType stream)
}
}
else if (csb_tail->csb_relation)
alias = csb_tail->csb_relation->rel_name.c_str();
alias = csb_tail->csb_relation->getName().c_str();
else if (csb_tail->csb_procedure)
alias = csb_tail->csb_procedure->getName().toString();
//// TODO: LocalTableSourceNode

View File

@ -1076,7 +1076,7 @@ InversionNode* Retrieval::makeIndexScanNode(IndexScratch* indexScratch) const
// For external requests, determine index name (to be reported in plans)
MetaName indexName;
if (!(csb->csb_g_flags & csb_internal))
MetadataCache::lookup_index(tdbb, indexName, relation->rel_name, idx->idx_id + 1);
MetadataCache::lookup_index(tdbb, indexName, relation->getName(), idx->idx_id + 1);
const auto retrieval =
FB_NEW_POOL(getPool()) IndexRetrieval(getPool(), relation, idx, indexName);

View File

@ -108,14 +108,14 @@ namespace
CompilerScratch::csb_repeat* t1 = CMP_csb_element(m_csb, 0);
t1->csb_flags |= csb_used | csb_active | csb_trigger;
t1->csb_relation = m_csb->csb_resources.registerResource(tdbb, Resource::rsc_relation,
relation, relation->rel_id);
relation, relation->getId());
t1->csb_stream = stream;
stream = m_csb->nextStream();
t1 = CMP_csb_element(m_csb, 1);
t1->csb_flags |= csb_used | csb_active | csb_trigger;
t1->csb_relation = m_csb->csb_resources.registerResource(tdbb, Resource::rsc_relation,
relation, relation->rel_id);
relation, relation->getId());
t1->csb_stream = stream;
}
else if (relation)
@ -123,7 +123,7 @@ namespace
CompilerScratch::csb_repeat* t1 = CMP_csb_element(m_csb, 0);
t1->csb_stream = m_csb->nextStream();
t1->csb_relation = m_csb->csb_resources.registerResource(tdbb, Resource::rsc_relation,
relation, relation->rel_id);
relation, relation->getId());
t1->csb_flags = csb_used | csb_active;
}
@ -479,7 +479,7 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item
if (csb->collectingDependencies())
{
CompilerScratch::Dependency dependency(obj_field);
Dependency dependency(obj_field);
dependency.name = name;
csb->addDependency(dependency);
}
@ -544,9 +544,9 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item
if (csb->collectingDependencies())
{
CompilerScratch::Dependency dependency(obj_relation);
Dependency dependency(obj_relation);
jrd_rel* rel = MetadataCache::lookup_relation(tdbb, *relationName);
dependency.relation = csb->csb_resources.registerResource(tdbb, Resource::rsc_relation, rel, rel->rel_id);
dependency.relation = csb->csb_resources.registerResource(tdbb, Resource::rsc_relation, rel, rel->getId());
dependency.subName = fieldName;
csb->addDependency(dependency);
}
@ -562,7 +562,7 @@ USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, dsc* desc, ItemInfo* item
if (csb->collectingDependencies() && desc->getTextType() != CS_NONE)
{
CompilerScratch::Dependency dependency(obj_collation);
Dependency dependency(obj_collation);
dependency.number = INTL_TEXT_TYPE(*desc);
csb->addDependency(dependency);
}
@ -609,7 +609,7 @@ ValueExprNode* PAR_make_field(thread_db* tdbb, CompilerScratch* csb, USHORT cont
*
* Functional description
* Make up a field node in the permanent pool. This is used
* by MET_scan_relation to handle view fields.
* by relation scan to handle view fields.
*
**************************************/
SET_TDBB(tdbb);
@ -892,7 +892,7 @@ void PAR_dependency(thread_db* tdbb, CompilerScratch* csb, StreamType stream, SS
if (!csb->collectingDependencies())
return;
CompilerScratch::Dependency dependency(0);
Dependency dependency(0);
if (csb->csb_rpt[stream].csb_relation)
{
@ -1054,12 +1054,12 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (isGbak)
{
PAR_warning(Arg::Warning(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
else
{
PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
}
else if (idx_status == MET_object_deferred_active)
@ -1067,7 +1067,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (!isGbak)
{
PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
}
@ -1082,7 +1082,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (csb->collectingDependencies())
{
CompilerScratch::Dependency dependency(obj_index);
Dependency dependency(obj_index);
dependency.name = &item.indexName;
csb->addDependency(dependency);
}
@ -1123,12 +1123,12 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (isGbak)
{
PAR_warning(Arg::Warning(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
else
{
PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
}
else if (idx_status == MET_object_deferred_active)
@ -1136,7 +1136,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (!isGbak)
{
PAR_error(csb, Arg::Gds(isc_indexname) << Arg::Str(name) <<
Arg::Str(relation->rel_name));
Arg::Str(relation->getName()));
}
}
@ -1151,7 +1151,7 @@ static PlanNode* par_plan(thread_db* tdbb, CompilerScratch* csb)
if (csb->collectingDependencies())
{
CompilerScratch::Dependency dependency(obj_index);
Dependency dependency(obj_index);
dependency.name = &item.indexName;
csb->addDependency(dependency);
}
@ -1390,7 +1390,6 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
break;
case blr_writelock:
// PAR_parseRecordSource() called RelationSourceNode::parse() => MET_scan_relation().
for (FB_SIZE_T iter = 0; iter < rse->rse_relations.getCount(); ++iter)
{
const RelationSourceNode* subNode = nodeAs<RelationSourceNode>(rse->rse_relations[iter]);
@ -1400,11 +1399,11 @@ RseNode* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
const jrd_rel* relation = relNode->relation;
fb_assert(relation);
if (relation->isVirtual())
PAR_error(csb, Arg::Gds(isc_forupdate_virtualtbl) << relation->rel_name, false);
PAR_error(csb, Arg::Gds(isc_forupdate_virtualtbl) << relation->getName(), false);
if (relation->isSystem())
PAR_error(csb, Arg::Gds(isc_forupdate_systbl) << relation->rel_name, false);
PAR_error(csb, Arg::Gds(isc_forupdate_systbl) << relation->getName(), false);
if (relation->isTemporary())
PAR_error(csb, Arg::Gds(isc_forupdate_temptbl) << relation->rel_name, false);
PAR_error(csb, Arg::Gds(isc_forupdate_temptbl) << relation->getName(), false);
}
rse->flags |= RseNode::FLAG_WRITELOCK;
break;

View File

@ -132,7 +132,7 @@ void BitmapTableScan::print(thread_db* tdbb, string& plan,
if (detailed)
{
plan += printIndent(++level) + "Table " +
printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Access By ID";
printName(tdbb, m_relation->getName().c_str(), m_alias) + " Access By ID";
printOptInfo(plan);
printInversion(tdbb, m_inversion, plan, true, level);

View File

@ -125,7 +125,7 @@ void ExternalTableScan::print(thread_db* tdbb, string& plan,
if (detailed)
{
plan += printIndent(++level) + "Table " +
printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan";
printName(tdbb, m_relation->getName().c_str(), m_alias) + " Full Scan";
printOptInfo(plan);
}
else

View File

@ -189,7 +189,7 @@ void FullTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigned
bounds += " (upper bound)";
plan += printIndent(++level) + "Table " +
printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan" + bounds;
printName(tdbb, m_relation->getName().c_str(), m_alias) + " Full Scan" + bounds;
printOptInfo(plan);
}
else

View File

@ -312,7 +312,7 @@ void IndexTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsigne
if (detailed)
{
plan += printIndent(++level) + "Table " +
printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Access By ID";
printName(tdbb, m_relation->getName().c_str(), m_alias) + " Access By ID";
printOptInfo(plan);
printInversion(tdbb, m_index, plan, true, level, true);

View File

@ -361,7 +361,7 @@ namespace Jrd
public:
ProcedureScan(CompilerScratch* csb, const Firebird::string& alias, StreamType stream,
const jrd_prc* procedure, const ValueListNode* sourceList,
const SubRoutine<jrd_prc>& procedure, const ValueListNode* sourceList,
const ValueListNode* targetList, MessageNode* message);
void close(thread_db* tdbb) const override;

View File

@ -478,7 +478,7 @@ void SortedStream::mapData(thread_db* tdbb, Request* request, UCHAR* data) const
if (!DPM_get(tdbb, &temp, LCK_read))
Arg::Gds(isc_no_cur_rec).raise();
tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, relation->getId());
if (VIO_chase_record_version(tdbb, &temp, transaction, tdbb->getDefaultPool(), false, false))
{

View File

@ -118,7 +118,7 @@ void VirtualTableScan::print(thread_db* tdbb, string& plan, bool detailed, unsig
if (detailed)
{
plan += printIndent(++level) + "Table " +
printName(tdbb, m_relation->rel_name.c_str(), m_alias) + " Full Scan";
printName(tdbb, m_relation->getName().c_str(), m_alias) + " Full Scan";
printOptInfo(plan);
}
else

View File

@ -553,9 +553,6 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum,
if (!rel)
raiseError("Table %s is not found", relName.c_str());
if (!(rel->rel_flags & REL_scanned))
MET_scan_relation(tdbb, rel);
const auto relation = rel.getPointer();
const auto format = findFormat(tdbb, relation, length);
@ -690,9 +687,6 @@ void Applier::updateRecord(thread_db* tdbb, TraNumber traNum,
if (!rel)
raiseError("Table %s is not found", relName.c_str());
if (!(rel->rel_flags & REL_scanned))
MET_scan_relation(tdbb, rel);
const auto relation = rel.getPointer();
const auto orgFormat = findFormat(tdbb, relation, orgLength);
@ -832,9 +826,6 @@ void Applier::deleteRecord(thread_db* tdbb, TraNumber traNum,
if (!rel)
raiseError("Table %s is not found", relName.c_str());
if (!(rel->rel_flags & REL_scanned))
MET_scan_relation(tdbb, rel);
const auto relation = rel.getPointer();
const auto format = findFormat(tdbb, relation, length);
@ -1076,7 +1067,7 @@ bool Applier::lookupRecord(thread_db* tdbb,
RecordBitmap::reset(m_bitmap);
// Special case: RDB$DATABASE has no keys but it's guaranteed to have only one record
if (relation->rel_id == rel_database)
if (relation->getId() == rel_database)
{
RBM_SET(tdbb->getDefaultPool(), &m_bitmap, 0);
return false;
@ -1106,7 +1097,7 @@ bool Applier::lookupRecord(thread_db* tdbb,
{
const auto tab = &NO_KEY_TABLES[i];
if (tab->rel_id == relation->rel_id)
if (tab->rel_id == relation->getId())
{
table = tab;
break;
@ -1114,7 +1105,7 @@ bool Applier::lookupRecord(thread_db* tdbb,
}
if (!table)
raiseError("Table %s has no unique key", relation->rel_name.c_str());
raiseError("Table %s has no unique key", relation->getName().c_str());
const auto transaction = tdbb->getTransaction();
@ -1168,7 +1159,7 @@ const Format* Applier::findFormat(thread_db* tdbb, jrd_rel* relation, ULONG leng
if (format->fmt_length != length)
{
raiseError("Record format with length %u is not found for table %s",
length, relation->rel_name.c_str());
length, relation->getName().c_str());
}
return format;
@ -1210,7 +1201,7 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
fb_assert(blob);
blob->blb_sub_type = desc.getBlobSubType();
blob->blb_charset = desc.getCharSet();
blobId->set_permanent(relation->rel_id, DPM_store_blob(tdbb, blob, relation, record));
blobId->set_permanent(relation->getId(), DPM_store_blob(tdbb, blob, relation, record));
current->bli_materialized = true;
current->bli_blob_id = *blobId;
transaction->tra_blobs->fastRemove();
@ -1223,7 +1214,7 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
const ULONG num1 = blobId->bid_quad.bid_quad_high;
const ULONG num2 = blobId->bid_quad.bid_quad_low;
raiseError("Blob %u.%u is not found for table %s",
num1, num2, relation->rel_name.c_str());
num1, num2, relation->getName().c_str());
}
}
}
@ -1305,7 +1296,7 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR
fb_assert(blob);
blob->blb_sub_type = desc.getBlobSubType();
blob->blb_charset = desc.getCharSet();
dstBlobId->set_permanent(relation->rel_id, DPM_store_blob(tdbb, blob, relation, newRecord));
dstBlobId->set_permanent(relation->getId(), DPM_store_blob(tdbb, blob, relation, newRecord));
current->bli_materialized = true;
current->bli_blob_id = *dstBlobId;
transaction->tra_blobs->fastRemove();
@ -1318,7 +1309,7 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR
const ULONG num1 = dstBlobId->bid_quad.bid_quad_high;
const ULONG num2 = dstBlobId->bid_quad.bid_quad_low;
raiseError("Blob %u.%u is not found for table %s",
num1, num2, relation->rel_name.c_str());
num1, num2, relation->getName().c_str());
}
}
}

View File

@ -498,15 +498,15 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
const auto relation = rpb->rpb_relation;
fb_assert(relation);
if (relation->isTemporary())
if (relation->rel_perm->isTemporary())
return;
if (!relation->isSystem())
if (!relation->rel_perm->isSystem())
{
if (!relation->isReplicating(tdbb))
return;
if (!matchTable(tdbb, relation->rel_name))
if (!matchTable(tdbb, relation->getName()))
return;
}
@ -525,7 +525,7 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
ReplicatedRecordImpl replRecord(tdbb, relation, record);
replicator->insertRecord(&status,
relation->rel_name.c_str(),
relation->getName().c_str(),
&replRecord);
checkStatus(tdbb, status, transaction);
@ -540,15 +540,15 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb,
const auto relation = newRpb->rpb_relation;
fb_assert(relation);
if (relation->isTemporary())
if (relation->rel_perm->isTemporary())
return;
if (!relation->isSystem())
if (!relation->rel_perm->isSystem())
{
if (!relation->isReplicating(tdbb))
return;
if (!matchTable(tdbb, relation->rel_name))
if (!matchTable(tdbb, relation->getName()))
return;
}
@ -583,7 +583,7 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb,
ReplicatedRecordImpl replNewRecord(tdbb, relation, newRecord);
replicator->updateRecord(&status,
relation->rel_name.c_str(),
relation->getName().c_str(),
&replOrgRecord, &replNewRecord);
checkStatus(tdbb, status, transaction);
@ -598,15 +598,15 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
const auto relation = rpb->rpb_relation;
fb_assert(relation);
if (relation->isTemporary())
if (relation->rel_perm->isTemporary())
return;
if (!relation->isSystem())
if (!relation->rel_perm->isSystem())
{
if (!relation->isReplicating(tdbb))
return;
if (!matchTable(tdbb, relation->rel_name))
if (!matchTable(tdbb, relation->getName()))
return;
}
@ -625,7 +625,7 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction)
ReplicatedRecordImpl replRecord(tdbb, relation, record);
replicator->deleteRecord(&status,
relation->rel_name.c_str(),
relation->getName().c_str(),
&replRecord);
checkStatus(tdbb, status, transaction);

View File

@ -51,12 +51,13 @@ class Savepoint;
class Cursor;
class thread_db;
// record parameter block
struct record_param
struct RecordParameterBase
{
record_param()
: rpb_transaction_nr(0), rpb_relation(0), rpb_record(NULL), rpb_prior(NULL),
RecordParameterBase()
: rpb_transaction_nr(0), rpb_record(NULL), rpb_prior(NULL),
rpb_undo(NULL), rpb_format_number(0),
rpb_page(0), rpb_line(0),
rpb_f_page(0), rpb_f_line(0),
@ -69,11 +70,10 @@ struct record_param
RecordNumber rpb_number; // record number in relation
TraNumber rpb_transaction_nr; // transaction number
jrd_rel* rpb_relation; // relation of record
Record* rpb_record; // final record block
Record* rpb_prior; // prior record block if this is a delta record
Record* rpb_undo; // our first version of data if this is a second modification
USHORT rpb_format_number; // format number in relation
USHORT rpb_format_number; // format number in relation
ULONG rpb_page; // page number
USHORT rpb_line; // line number on page
@ -91,17 +91,37 @@ struct record_param
USHORT rpb_runtime_flags; // runtime flags
SSHORT rpb_org_scans; // relation scan count at stream open
protected:
struct win rpb_window;
};
struct record_param : public RecordParameterBase
{
record_param()
: RecordParameterBase(), rpb_relation(nullptr)
{ }
inline WIN& getWindow(thread_db* tdbb)
{
if (rpb_relation) {
rpb_window.win_page.setPageSpaceID(rpb_relation->getPages(tdbb)->rel_pg_space_id);
rpb_window.win_page.setPageSpaceID(rpb_relation->rel_perm->getPages(tdbb)->rel_pg_space_id);
}
return rpb_window;
}
private:
struct win rpb_window;
jrd_rel* rpb_relation; // relation of record
};
struct RecordParameter : public RecordParameterBase
{
RecordParameter()
: RecordParameterBase(), rpb_relation()
{ }
WIN& getWindow(thread_db* tdbb); // in Statement.cpp
Rsc::Rel rpb_relation; // relation of record
};
// Record flags must be an exact replica of ODS record header flags
@ -162,38 +182,6 @@ private:
};
// Set of objects cached per particular MDC version
class CacheObject;
class VersionedObjects : public pool_alloc_rpt<CacheObject*>,
public Firebird::RefCounted
{
public:
VersionedObjects(FB_SIZE_T cnt, MdcVersion ver);
FB_SIZE_T push(CacheObject* obj);
template <class OBJ>
OBJ* get(FB_SIZE_T n)
{
fb_assert(count == capacity);
fb_assert(n < count);
// ????? fb_assert(dynamic_cast<OBJ*>(data[n]));
return reinterpret_cast<OBJ*>(data[n]);
}
MdcVersion version; // version when created
private:
FB_SIZE_T count;
#ifdef DEV_BUILD
FB_SIZE_T capacity;
#endif
CacheObject* data[1];
};
// request block
class Request : public pool_alloc<type_req>
@ -434,6 +422,7 @@ public:
SnapshotData req_snapshot;
StatusXcp req_last_xcp; // last known exception
bool req_batch_mode;
Firebird::RefPtr<VersionedObjects> resources;
enum req_s {
req_evaluate,
@ -445,6 +434,7 @@ public:
req_unwind
} req_operation; // operation for next node
template <typename T> T* getImpure(unsigned offset)
{
return reinterpret_cast<T*>(&impureArea[offset]);
@ -516,9 +506,6 @@ public:
{
req_timeStampCache.validate(req_attachment->att_current_timezone);
}
private:
Firebird::RefPtr<VersionedObjects> currentVersion;
};
// Flags for req_flags

View File

@ -81,7 +81,7 @@ Lock* RLCK_reserve_relation(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rela
!(tdbb->tdbb_flags & TDBB_repl_in_progress))
{
// This condition is a workaround for nbackup
if (relation->rel_id != rel_backup_history)
if (relation->getId() != rel_backup_history)
ERR_post(Arg::Gds(isc_read_only_trans));
}
}
@ -123,7 +123,7 @@ Lock* RLCK_reserve_relation(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rela
if (!result)
{
string err;
err.printf("Acquire lock for relation (%s) failed", relation->rel_name.c_str());
err.printf("Acquire lock for relation (%s) failed", relation->getName().c_str());
ERR_append_status(tdbb->tdbb_status_vector, Arg::Gds(isc_random) << Arg::Str(err));
ERR_punt();
@ -148,7 +148,7 @@ Lock* RLCK_transaction_relation_lock(thread_db* tdbb, jrd_tra* transaction, jrd_
**************************************/
SET_TDBB(tdbb);
const ULONG relId = relation->rel_id;
const ULONG relId = relation->getId();
Lock* lock;
vec<Lock*>* vector = transaction->tra_relation_locks;

View File

@ -47,7 +47,7 @@ int traRpbList::PushRpb(record_param* value)
if (pos-- > 0)
{
traRpbListElement& prev = (*this)[pos];
if (prev.lr_rpb->rpb_relation->rel_id == value->rpb_relation->rel_id &&
if (prev.lr_rpb->rpb_relation->getId() == value->rpb_relation->getId() &&
prev.lr_rpb->rpb_number == value->rpb_number)
{
// we got the same record once more - mark for refetch

View File

@ -46,8 +46,8 @@ public:
static inline bool greaterThan(const traRpbListElement& i1, const traRpbListElement& i2)
{
return i1.lr_rpb->rpb_relation->rel_id != i2.lr_rpb->rpb_relation->rel_id ?
i1.lr_rpb->rpb_relation->rel_id > i2.lr_rpb->rpb_relation->rel_id :
return i1.lr_rpb->rpb_relation->rel_perm->rel_id != i2.lr_rpb->rpb_relation->rel_perm->rel_id ?
i1.lr_rpb->rpb_relation->rel_perm->rel_id > i2.lr_rpb->rpb_relation->rel_perm->rel_id :
i1.lr_rpb->rpb_number != i2.lr_rpb->rpb_number ?
i1.lr_rpb->rpb_number > i2.lr_rpb->rpb_number :
i1.level > i2.level;

View File

@ -910,7 +910,6 @@ SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const TEXT* relation_name,
jrd_rel* relation;
if (relation_name && (relation = MetadataCache::lookup_relation(tdbb, relation_name)))
{
MET_scan_relation(tdbb, relation);
const SecurityClass* s_class;
if ( (s_class = SCL_get_class(tdbb, relation->rel_security_name.c_str())) )
{

511
src/jrd/tdbb.h Normal file
View File

@ -0,0 +1,511 @@
/*
* PROGRAM: JRD access method
* MODULE: tdbb.h
* DESCRIPTION: Thread specific database block
*
* 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_TDBB_H
#define JRD_TDBB_H
#include <cds/threading/model.h> // cds::threading::Manager
#include "../common/gdsassert.h"
#include "../common/classes/Synchronize.h"
#include "../jrd/RuntimeStatistics.h"
#include "../jrd/status.h"
#include "../jrd/err_proto.h"
#define BUGCHECK(number) ERR_bugcheck(number, __FILE__, __LINE__)
namespace Firebird {
class MemoryPool;
}
namespace Jrd
{
class Database;
class Attachment;
class jrd_tra;
class Request;
class BufferDesc;
class Lock;
class NullClass
{
public:
NullClass(MemoryPool&, MetaId, Lock*) { }
NullClass() { }
};
template <class OBJ, class EXT> class CacheElement;
#ifdef USE_ITIMER
class TimeoutTimer final :
public Firebird::RefCntIface<Firebird::ITimerImpl<TimeoutTimer, Firebird::CheckStatusWrapper> >
{
public:
explicit TimeoutTimer()
: m_started(0),
m_expired(false),
m_value(0),
m_error(0)
{ }
// ITimer implementation
void handler();
bool expired() const
{
return m_expired;
}
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// evaluate expire timestamp using start timestamp
bool getExpireTimestamp(const ISC_TIMESTAMP_TZ start, ISC_TIMESTAMP_TZ& exp) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 m_started;
bool m_expired;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#else
class TimeoutTimer : public Firebird::RefCounted
{
public:
explicit TimeoutTimer()
: m_start(0),
m_value(0),
m_error(0)
{ }
bool expired() const;
unsigned int getValue() const
{
return m_value;
}
unsigned int getErrCode() const
{
return m_error;
}
// milliseconds left before timer expiration
unsigned int timeToExpire() const;
// clock value when timer will expire
bool getExpireClock(SINT64& clock) const;
// set timeout value in milliseconds and secondary error code
void setup(unsigned int value, ISC_STATUS error)
{
m_start = 0;
m_value = value;
m_error = error;
}
void start();
void stop();
private:
SINT64 currTime() const
{
return fb_utils::query_performance_counter() * 1000 / fb_utils::query_performance_frequency();
}
SINT64 m_start;
unsigned int m_value; // milliseconds
ISC_STATUS m_error;
};
#endif // USE_ITIMER
// tdbb_flags
const ULONG TDBB_sweeper = 1; // Thread sweeper or garbage collector
const ULONG TDBB_no_cache_unwind = 2; // Don't unwind page buffer cache
const ULONG TDBB_backup_write_locked = 4; // BackupManager has write lock on LCK_backup_database
const ULONG TDBB_stack_trace_done = 8; // PSQL stack trace is added into status-vector
const ULONG TDBB_dont_post_dfw = 16; // dont post DFW tasks as deferred work is performed now
const ULONG TDBB_sys_error = 32; // error shouldn't be handled by the looper
const ULONG TDBB_verb_cleanup = 64; // verb cleanup is in progress
const ULONG TDBB_use_db_page_space = 128; // use database (not temporary) page space in GTT operations
const ULONG TDBB_detaching = 256; // detach is in progress
const ULONG TDBB_wait_cancel_disable = 512; // don't cancel current waiting operation
const ULONG TDBB_cache_unwound = 1024; // page cache was unwound
const ULONG TDBB_reset_stack = 2048; // stack should be reset after stack overflow exception
const ULONG TDBB_dfw_cleanup = 4096; // DFW cleanup phase is active
const ULONG TDBB_repl_in_progress = 8192; // Prevent recursion in replication
const ULONG TDBB_replicator = 16384; // Replicator
class thread_db : public Firebird::ThreadData
{
const static int QUANTUM = 100; // Default quantum
const static int SWEEP_QUANTUM = 10; // Make sweeps less disruptive
private:
MemoryPool* defaultPool;
void setDefaultPool(MemoryPool* p)
{
defaultPool = p;
}
friend class Firebird::SubsystemContextPoolHolder <Jrd::thread_db, MemoryPool>;
Database* database;
Attachment* attachment;
jrd_tra* transaction;
Request* request;
RuntimeStatistics *reqStat, *traStat, *attStat, *dbbStat;
public:
explicit thread_db(FbStatusVector* status)
: ThreadData(ThreadData::tddDBB),
defaultPool(NULL),
database(NULL),
attachment(NULL),
transaction(NULL),
request(NULL),
tdbb_status_vector(status),
tdbb_quantum(QUANTUM),
tdbb_flags(0),
tdbb_temp_traid(0),
tdbb_bdbs(*getDefaultMemoryPool()),
tdbb_thread(Firebird::ThreadSync::getThread("thread_db"))
{
reqStat = traStat = attStat = dbbStat = RuntimeStatistics::getDummy();
fb_utils::init_status(tdbb_status_vector);
}
~thread_db()
{
resetStack();
#ifdef DEV_BUILD
for (FB_SIZE_T n = 0; n < tdbb_bdbs.getCount(); ++n)
{
fb_assert(tdbb_bdbs[n] == NULL);
}
#endif
}
FbStatusVector* tdbb_status_vector;
SLONG tdbb_quantum; // Cycles remaining until voluntary schedule
ULONG tdbb_flags;
TraNumber tdbb_temp_traid; // current temporary table scope
// BDB's held by thread
Firebird::HalfStaticArray<BufferDesc*, 16> tdbb_bdbs;
Firebird::ThreadSync* tdbb_thread;
MemoryPool* getDefaultPool()
{
return defaultPool;
}
Database* getDatabase()
{
return database;
}
const Database* getDatabase() const
{
return database;
}
void setDatabase(Database* val);
Attachment* getAttachment()
{
return attachment;
}
const Attachment* getAttachment() const
{
return attachment;
}
void setAttachment(Attachment* val);
jrd_tra* getTransaction()
{
return transaction;
}
const jrd_tra* getTransaction() const
{
return transaction;
}
void setTransaction(jrd_tra* val);
Request* getRequest()
{
return request;
}
const Request* getRequest() const
{
return request;
}
void setRequest(Request* val);
SSHORT getCharSet() const;
void markAsSweeper()
{
tdbb_quantum = SWEEP_QUANTUM;
tdbb_flags |= TDBB_sweeper;
}
void bumpStats(const RuntimeStatistics::StatType index, SINT64 delta = 1)
{
reqStat->bumpValue(index, delta);
traStat->bumpValue(index, delta);
attStat->bumpValue(index, delta);
dbbStat->bumpValue(index, delta);
}
void bumpRelStats(const RuntimeStatistics::StatType index, SLONG relation_id, SINT64 delta = 1)
{
// We don't bump counters for dbbStat here, they're merged from attStats on demand
reqStat->bumpValue(index, delta);
traStat->bumpValue(index, delta);
attStat->bumpValue(index, delta);
const RuntimeStatistics* const dummyStat = RuntimeStatistics::getDummy();
// We expect that at least attStat is present (not a dummy object)
fb_assert(attStat != dummyStat);
// Relation statistics is a quite complex beast, so a conditional check
// does not hurt. It also allows to avoid races while accessing the static
// dummy object concurrently.
if (reqStat != dummyStat)
reqStat->bumpRelValue(index, relation_id, delta);
if (traStat != dummyStat)
traStat->bumpRelValue(index, relation_id, delta);
if (attStat != dummyStat)
attStat->bumpRelValue(index, relation_id, delta);
}
ISC_STATUS getCancelState(ISC_STATUS* secondary = NULL);
void checkCancelState();
void reschedule();
const TimeoutTimer* getTimeoutTimer() const
{
return tdbb_reqTimer;
}
// Returns minimum of passed wait timeout and time to expiration of reqTimer.
// Timer value is rounded to the upper whole second.
ULONG adjustWait(ULONG wait) const;
void registerBdb(BufferDesc* bdb)
{
if (tdbb_bdbs.isEmpty()) {
tdbb_flags &= ~TDBB_cache_unwound;
}
fb_assert(!(tdbb_flags & TDBB_cache_unwound));
FB_SIZE_T pos;
if (tdbb_bdbs.find(NULL, pos))
tdbb_bdbs[pos] = bdb;
else
tdbb_bdbs.add(bdb);
}
bool clearBdb(BufferDesc* bdb)
{
if (tdbb_bdbs.isEmpty())
{
// hvlad: the only legal case when thread holds no latches but someone
// tried to release latch is when CCH_unwind was called (and released
// all latches) but caller is unaware about it. See CORE-3034, for example.
// Else it is bug and should be BUGCHECK'ed.
if (tdbb_flags & TDBB_cache_unwound)
return false;
}
fb_assert(!(tdbb_flags & TDBB_cache_unwound));
FB_SIZE_T pos;
if (!tdbb_bdbs.find(bdb, pos))
BUGCHECK(300); // can't find shared latch
tdbb_bdbs[pos] = NULL;
if (pos == tdbb_bdbs.getCount() - 1)
{
while (true)
{
if (tdbb_bdbs[pos] != NULL)
{
tdbb_bdbs.shrink(pos + 1);
break;
}
if (pos == 0)
{
tdbb_bdbs.shrink(0);
break;
}
--pos;
}
}
return true;
}
void resetStack()
{
if (tdbb_flags & TDBB_reset_stack)
{
tdbb_flags &= ~TDBB_reset_stack;
#ifdef WIN_NT
_resetstkoflw();
#endif
}
}
class TimerGuard
{
public:
TimerGuard(thread_db* tdbb, TimeoutTimer* timer, bool autoStop)
: m_tdbb(tdbb),
m_autoStop(autoStop && timer),
m_saveTimer(tdbb->tdbb_reqTimer)
{
m_tdbb->tdbb_reqTimer = timer;
if (timer && timer->expired())
m_tdbb->tdbb_quantum = 0;
}
~TimerGuard()
{
if (m_autoStop)
m_tdbb->tdbb_reqTimer->stop();
m_tdbb->tdbb_reqTimer = m_saveTimer;
}
private:
thread_db* m_tdbb;
bool m_autoStop;
Firebird::RefPtr<TimeoutTimer> m_saveTimer;
};
private:
Firebird::RefPtr<TimeoutTimer> tdbb_reqTimer;
};
class ThreadContextHolder
{
public:
explicit ThreadContextHolder(Firebird::CheckStatusWrapper* status = NULL)
: context(status ? status : &localStatus)
{
context.putSpecific();
if (!cds::threading::Manager::isThreadAttached())
cds::threading::Manager::attachThread();
}
ThreadContextHolder(Database* dbb, Jrd::Attachment* att, FbStatusVector* status = NULL)
: context(status ? status : &localStatus)
{
context.putSpecific();
context.setDatabase(dbb);
context.setAttachment(att);
if (!cds::threading::Manager::isThreadAttached())
cds::threading::Manager::attachThread();
}
~ThreadContextHolder()
{
Firebird::ThreadData::restoreSpecific();
}
thread_db* operator->()
{
return &context;
}
operator thread_db*()
{
return &context;
}
private:
// copying is prohibited
ThreadContextHolder(const ThreadContextHolder&);
ThreadContextHolder& operator= (const ThreadContextHolder&);
Firebird::FbLocalStatus localStatus;
thread_db context;
};
} // namespace Jrd
#endif // JRD_TDBB_H

View File

@ -2179,11 +2179,11 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel
Arg::Gds(isc_tpb_reserv_max_recursion) << Arg::Num(30));
}
const char* const relation_name = relation->rel_name.c_str();
const char* const relation_name = relation->getName().c_str();
// LCK_none < LCK_SR < LCK_PR < LCK_SW < LCK_EX
UCHAR oldlock;
const bool found = lockmap.get(relation->rel_id, oldlock);
const bool found = lockmap.get(relation->getId(), oldlock);
if (found && oldlock > lock_type)
{
@ -2258,7 +2258,7 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel
lock->lck_logical = lock_type;
if (!found)
*lockmap.put(relation->rel_id) = lock_type;
*lockmap.put(relation->getId()) = lock_type;
const ViewContexts& ctx = relation->rel_view_contexts;
@ -2277,9 +2277,6 @@ static void expand_view_lock(thread_db* tdbb, jrd_tra* transaction, jrd_rel* rel
Arg::Str(option_name));
}
// force a scan to read view information
MET_scan_relation(tdbb, base_rel);
expand_view_lock(tdbb, transaction, base_rel, lock_type, option_name, lockmap, level + 1);
}
}
@ -3202,9 +3199,6 @@ static void transaction_options(thread_db* tdbb,
Arg::Str(option_name));
}
// force a scan to read view information
MET_scan_relation(tdbb, relation);
UCHAR lock_type = (op == isc_tpb_lock_read) ? LCK_none : LCK_SW;
if (tpb < end)
{
@ -4065,11 +4059,7 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool
{
const MetaName security_name = (fld && fld->fld_security_name.hasData()) ?
fld->fld_security_name : blobRelation->rel_security_name;
if (security_name.isEmpty())
{
MET_scan_relation(tdbb, blobRelation);
security_name = blb_relation->rel_security_name;
}
fb_assert(security_name.hasData());
SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str());
if (!s_class)
@ -4086,12 +4076,12 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool
if (fld)
{
SCL_check_access(tdbb, s_class, 0, 0, SCL_select, obj_column,
false, fld->fld_name, blobRelation->rel_name);
false, fld->fld_name, blobRelation->getName());
}
else
{
SCL_check_access(tdbb, s_class, 0, 0, SCL_select, obj_relations,
false, blobRelation->rel_name);
false, blobRelation->getName());
}
s_class->scl_blb_access = SecurityClass::BA_SUCCESS;
@ -4121,7 +4111,7 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool
{
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("SELECT") <<
(fld ? Arg::Str("COLUMN") : Arg::Str("TABLE")) <<
(fld ? Arg::Str(fld->fld_name) : Arg::Str(blobRelation->rel_name)));
(fld ? Arg::Str(fld->fld_name) : Arg::Str(blobRelation->getName())));
}
else
tra_fetched_blobs.add(*blob_id);
@ -4187,10 +4177,10 @@ void TraceSweepEvent::beginSweepRelation(const jrd_rel* relation)
if (!m_need_trace)
return;
if (relation && relation->rel_name.isEmpty())
if (relation && relation->getName().isEmpty())
{
// don't accumulate per-relation stats for metadata query below
MetadataCache::lookup_relation_id(m_tdbb, relation->rel_id, false);
MetadataCache::lookup_relation_id(m_tdbb, relation->getId(), false);
}
m_relation_clock = fb_utils::query_performance_counter();

View File

@ -67,6 +67,7 @@ class UserManagement;
class MappingList;
class DbCreatorsList;
class thread_db;
class Resources;
class SecDbContext
{
@ -404,6 +405,8 @@ public:
return tra_gen_ids;
}
void postResources(thread_db* tdbb, const Resources* resources);
};
// System transaction is always transaction 0.

View File

@ -499,7 +499,7 @@ const char* TraceTriggerImpl::getRelationName()
return NULL;
const jrd_rel* rel = m_trig->req_rpb[0].rpb_relation;
return rel ? rel->rel_name.c_str() : NULL;
return rel ? rel->getName().c_str() : NULL;
}

View File

@ -1134,7 +1134,7 @@ Validation::RTN Validation::corrupt(int err_code, const jrd_rel* relation, ...)
if (relation)
{
fprintf(stdout, "LOG:\tDatabase: %s\n\t%s in table %s (%d)\n",
fn, s.c_str(), relation->rel_name.c_str(), relation->rel_id);
fn, s.c_str(), relation->getName().c_str(), relation->getId());
}
else
fprintf(stdout, "LOG:\tDatabase: %s\n\t%s\n", fn, s.c_str());
@ -1154,7 +1154,7 @@ Validation::RTN Validation::corrupt(int err_code, const jrd_rel* relation, ...)
if (relation)
{
gds__log("Database: %s\n\t%s in table %s (%d)",
fn, s.c_str(), relation->rel_name.c_str(), relation->rel_id);
fn, s.c_str(), relation->getName().c_str(), relation->getId());
}
else
gds__log("Database: %s\n\t%s", fn, s.c_str());
@ -1558,7 +1558,7 @@ Validation::RTN Validation::walk_chain(jrd_rel* relation, const rhd* header,
data_page* page = 0;
fetch_page(true, page_number, pag_data, &window, &page);
if (page->dpg_relation != relation->rel_id)
if (page->dpg_relation != relation->getId())
{
release_page(&window);
return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, page->dpg_sequence);
@ -1647,13 +1647,13 @@ void Validation::walk_database()
if (vdr_tab_incl)
{
if (!vdr_tab_incl->matches(relation->rel_name.c_str(), relation->rel_name.length()))
if (!vdr_tab_incl->matches(relation->getName().c_str(), relation->getName().length()))
continue;
}
if (vdr_tab_excl)
{
if (vdr_tab_excl->matches(relation->rel_name.c_str(), relation->rel_name.length()))
if (vdr_tab_excl->matches(relation->getName().c_str(), relation->getName().length()))
continue;
}
@ -1663,7 +1663,7 @@ void Validation::walk_database()
vdr_page_bitmap->clear();
string relName;
relName.printf("Relation %d (%s)", relation->rel_id, relation->rel_name.c_str());
relName.printf("Relation %d (%s)", relation->getId(), relation->getName().c_str());
output("%s\n", relName.c_str());
int errs = vdr_errors;
@ -1713,7 +1713,7 @@ Validation::RTN Validation::walk_data_page(jrd_rel* relation, ULONG page_number,
}
#endif
if (page->dpg_relation != relation->rel_id || page->dpg_sequence != sequence)
if (page->dpg_relation != relation->getId() || page->dpg_sequence != sequence)
{
release_page(&window);
return corrupt(VAL_DATA_PAGE_CONFUSED, relation, page_number, sequence);
@ -2064,7 +2064,7 @@ Validation::RTN Validation::walk_index(jrd_rel* relation, index_root_page& root_
const bool leafPage = (page->btr_level == 0);
if (page->btr_relation != relation->rel_id || page->btr_id != (UCHAR) (id % 256))
if (page->btr_relation != relation->getId() || page->btr_id != (UCHAR) (id % 256))
{
corrupt(VAL_INDEX_PAGE_CORRUPT, relation, id + 1,
next, page->btr_level, 0, __FILE__, __LINE__);
@ -2583,13 +2583,13 @@ Validation::RTN Validation::walk_pointer_page(jrd_rel* relation, ULONG sequence)
if (VAL_debug_level)
{
fprintf(stdout, "walk_pointer_page: page %d relation %d sequence %d\n",
(*vector)[sequence], relation->rel_id, sequence);
(*vector)[sequence], relation->getId(), sequence);
}
#endif
// Give the page a quick once over
if (page->ppg_relation != relation->rel_id || page->ppg_sequence != sequence)
if (page->ppg_relation != relation->getId() || page->ppg_sequence != sequence)
{
release_page(&window);
return corrupt(VAL_P_PAGE_INCONSISTENT, relation, (*vector)[sequence], sequence);
@ -2809,7 +2809,7 @@ Validation::RTN Validation::walk_record(jrd_rel* relation, const rhd* header, US
const data_page::dpg_repeat* line = &page->dpg_rpt[line_number];
if (page->dpg_relation != relation->rel_id ||
if (page->dpg_relation != relation->getId() ||
line_number >= page->dpg_count || !(length = line->dpg_length))
{
corrupt(VAL_REC_FRAGMENT_CORRUPT, relation, number.getValue());
@ -3005,7 +3005,7 @@ void Validation::checkDPinPIP(jrd_rel* relation, ULONG page_number)
release_page(&pip_window);
}
Validation::RTN Validation::walk_relation(jrd_rel* rel)
Validation::RTN Validation::walk_relation(jrd_rel* relation)
{
/**************************************
*
@ -3020,14 +3020,6 @@ Validation::RTN Validation::walk_relation(jrd_rel* rel)
try {
// If relation hasn't been scanned, do so now
if (!(rel->rel_flags & REL_scanned) || (rel->rel_flags & REL_being_scanned))
{
MET_scan_relation(vdr_tdbb, rel);
}
jrd_rel* relation = rel.getPointer();
// skip deleted relations
if (relation->rel_flags & (REL_deleted | REL_deleting)) {
return rtn_ok;
@ -3036,8 +3028,8 @@ Validation::RTN Validation::walk_relation(jrd_rel* rel)
#ifdef DEBUG_VAL_VERBOSE
if (VAL_debug_level)
fprintf(stdout, "walk_relation: id %d Format %d %s %s\n",
relation->rel_id, relation->rel_current_fmt,
relation->rel_name.c_str(), relation->rel_owner_name.c_str());
relation->getId(), relation->rel_current_fmt,
relation->getName().c_str(), relation->rel_owner_name.c_str());
#endif
// If it's a view, external file or virtual table, skip this
@ -3164,16 +3156,16 @@ Validation::RTN Validation::walk_relation(jrd_rel* rel)
{
if (!(vdr_flags & VDR_online))
{
const char* msg = rel->rel_name.length() > 0 ?
const char* msg = rel->getName().length() > 0 ?
"bugcheck during scan of table %d (%s)" :
"bugcheck during scan of table %d";
gds__log(msg, rel->rel_id, rel->rel_name.c_str());
gds__log(msg, rel->getId(), rel->getName().c_str());
}
#ifdef DEBUG_VAL_VERBOSE
if (VAL_debug_level)
{
char s[256];
SNPRINTF(s, sizeof(s), msg, rel->rel_id, rel->rel_name.c_str());
SNPRINTF(s, sizeof(s), msg, rel->getId(), rel->getName().c_str());
fprintf(stdout, "LOG:\t%s\n", s);
}
#endif
@ -3216,7 +3208,7 @@ Validation::RTN Validation::walk_root(jrd_rel* relation, bool getInfo)
MetaName index;
release_page(&window);
MetadataCache::lookup_index(vdr_tdbb, index, relation->rel_name, i + 1);
MetadataCache::lookup_index(vdr_tdbb, index, relation->getName(), i + 1);
fetch_page(false, relPages->rel_index_root, pag_root, &window, &page);
if (vdr_idx_incl)

View File

@ -442,7 +442,7 @@ bool SweepTask::handler(WorkItem& _item)
if (!gcGuard.gcEnabled())
{
string str;
str.printf("Acquire garbage collection lock failed (%s)", relation->rel_name.c_str());
str.printf("Acquire garbage collection lock failed (%s)", relation->getName().c_str());
status_exception::raise(Arg::Gds(isc_random) << Arg::Str(str));
}
@ -634,10 +634,10 @@ static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio
return false;
vec<Lock*>* vector = transaction->tra_relation_locks;
if (!vector || relation->rel_id >= vector->count())
if (!vector || relation->getId() >= vector->count())
return false;
Lock* lock = (*vector)[relation->rel_id];
Lock* lock = (*vector)[relation->getId()];
if (!lock)
return false;
@ -659,7 +659,7 @@ inline void check_gbak_cheating_insupd(thread_db* tdbb, const jrd_rel* relation,
!request->hasInternalStatement())
{
status_exception::raise(Arg::Gds(isc_protect_sys_tab) <<
Arg::Str(op) << Arg::Str(relation->rel_name));
Arg::Str(op) << Arg::Str(relation->getName()));
}
}
@ -679,7 +679,7 @@ inline void check_gbak_cheating_delete(thread_db* tdbb, const jrd_rel* relation)
// There are 2 tables whose contents gbak might delete:
// - RDB$INDEX_SEGMENTS if it detects inconsistencies while restoring
// - RDB$FILES if switch -k is set
switch(relation->rel_id)
switch(relation->getId())
{
case rel_segments:
case rel_files:
@ -694,7 +694,7 @@ inline void check_gbak_cheating_delete(thread_db* tdbb, const jrd_rel* relation)
inline int wait(thread_db* tdbb, jrd_tra* transaction, const record_param* rpb)
{
if (transaction->getLockWait())
tdbb->bumpRelStats(RuntimeStatistics::RECORD_WAITS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_WAITS, rpb->rpb_relation->getId());
return TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait);
}
@ -833,7 +833,7 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_backout (rel_id %u, record_param %" SQUADFORMAT", transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
#endif
// If there is data in the record, fetch it now. If the old version
@ -1018,7 +1018,7 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction)
gcLockGuard.release();
delete_record(tdbb, rpb, 0, NULL);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation->getId());
return;
}
@ -1108,7 +1108,7 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction)
delete_record(tdbb, &temp, rpb->rpb_page, NULL);
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation->getId());
}
@ -1144,7 +1144,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb,
VIO_trace(DEBUG_TRACE_ALL,
"VIO_chase_record_version (rel_id %u, record_param %" QUADFORMAT"d, transaction %"
SQUADFORMAT", pool %p)\n",
relation->rel_id,
relation->getId(),
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
@ -1308,7 +1308,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb,
if (state == tra_active)
{
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->getId());
// Cannot use Arg::Num here because transaction number is 64-bit unsigned integer
ERR_post(Arg::Gds(isc_deadlock) <<
@ -1775,7 +1775,7 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_READS,
"VIO_data (rel_id %u, record_param %" QUADFORMAT"d, pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), (void*)pool);
relation->getId(), rpb->rpb_number.getValue(), (void*)pool);
VIO_trace(DEBUG_READS_INFO,
@ -1960,7 +1960,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_erase (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction->tra_number);
relation->getId(), rpb->rpb_number.getValue(), transaction->tra_number);
VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -2007,7 +2007,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
USHORT id;
DeferredWork* work;
switch ((RIDS) relation->rel_id)
switch ((RIDS) relation->getId())
{
case rel_database:
case rel_log:
@ -2060,9 +2060,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
}
EVL_field(0, rpb->rpb_record, f_rel_name, &desc);
DFW_post_work(transaction, dfw_delete_relation, &desc, id);
jrd_rel* rel_drop = MetadataCache::lookup_relation_id(tdbb, id, false);
if (rel_drop)
MET_scan_relation(tdbb, rel_drop);
MetadataCache::lookup_relation_id(tdbb, id, false);
}
break;
@ -2135,7 +2133,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
// hvlad: lets add index name to the DFW item even if we add it again later within
// additional argument. This is needed to make DFW work items different for different
// indexes dropped at the same transaction and to not merge them at DFW_merge_work.
work = DFW_post_work(transaction, dfw_delete_index, &idx_name, r2->rel_id);
work = DFW_post_work(transaction, dfw_delete_index, &idx_name, r2->getId());
// add index id and name (the latter is required to delete dependencies correctly)
DFW_post_work_arg(transaction, work, &idx_name, id, dfw_arg_index_name);
@ -2156,7 +2154,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
MET_lookup_partner(tdbb, r2.getPointer(), &idx, index_name.nullStr()) &&
(partner = MetadataCache::lookup_relation_id(tdbb, idx.idx_primary_relation, false)) )
{
DFW_post_work_arg(transaction, work, 0, partner->rel_id,
DFW_post_work_arg(transaction, work, 0, partner->getId(),
dfw_arg_partner_rel_id);
}
else
@ -2179,7 +2177,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
EVL_field(0, rpb->rpb_record, f_rfr_fname, &desc2);
MOV_get_metaname(tdbb, &desc, object_name);
if ( (r2 = MetadataCache::lookup_relation(tdbb, object_name)) )
DFW_post_work(transaction, dfw_delete_rfr, &desc2, r2->rel_id);
DFW_post_work(transaction, dfw_delete_rfr, &desc2, r2->getId());
EVL_field(0, rpb->rpb_record, f_rfr_sname, &desc2);
MOV_get_metaname(tdbb, &desc2, object_name);
@ -2344,7 +2342,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
if ((dbb->dbb_flags & DBB_gc_background) && !rpb->rpb_relation->isTemporary() && !backVersion)
notify_garbage_collector(tdbb, rpb, transaction->tra_number);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->getId());
return true;
}
@ -2382,7 +2380,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
// Check to see if recursive revoke needs to be propagated
if ((RIDS) relation->rel_id == rel_priv)
if ((RIDS) relation->getId() == rel_priv)
{
EVL_field(0, rpb->rpb_record, f_prv_rname, &desc);
MOV_get_metaname(tdbb, &desc, object_name);
@ -2401,7 +2399,7 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
if (transaction->tra_save_point && transaction->tra_save_point->isChanging())
verb_post(tdbb, transaction, rpb, 0);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->getId());
// for an autocommit transaction, mark a commit as necessary
@ -2732,7 +2730,7 @@ void VIO_intermediate_gc(thread_db* tdbb, record_param* rpb, jrd_tra* transactio
clearRecordStack(staying);
clearRecordStack(going);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IMGC, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IMGC, rpb->rpb_relation->getId());
}
bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
@ -2759,7 +2757,7 @@ bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, jrd_tra* transactio
VIO_trace(DEBUG_TRACE,
"VIO_garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, transaction %"
SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_TRACE_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -2894,7 +2892,7 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPoo
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"VIO_get (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
#endif
@ -2936,7 +2934,7 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPoo
VIO_data(tdbb, rpb, pool);
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IDX_READS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IDX_READS, rpb->rpb_relation->getId());
return true;
}
@ -2972,7 +2970,7 @@ bool VIO_get_current(thread_db* tdbb,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_get_current (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
#endif
@ -3011,7 +3009,7 @@ bool VIO_get_current(thread_db* tdbb,
if (!counted)
{
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IDX_READS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_IDX_READS, rpb->rpb_relation->getId());
counted = true;
}
@ -3250,7 +3248,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
VIO_trace(DEBUG_WRITES,
"VIO_modify (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, "
"transaction %" SQUADFORMAT")\n",
relation->rel_id, org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(),
relation->getId(), org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(),
transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
@ -3294,7 +3292,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
if (transaction->tra_flags & TRA_system)
{
VIO_update_in_place(tdbb, transaction, org_rpb, new_rpb);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->getId());
return true;
}
@ -3309,7 +3307,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
{
const SLONG nullLinger = 0;
switch ((RIDS) relation->rel_id)
switch ((RIDS) relation->getId())
{
case rel_segments:
case rel_vrel:
@ -3654,7 +3652,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
verb_post(tdbb, transaction, org_rpb, org_rpb->rpb_undo);
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->getId());
return true;
}
@ -3687,7 +3685,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
verb_post(tdbb, transaction, org_rpb, 0);
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->getId());
// for an autocommit transaction, mark a commit as necessary
@ -3745,7 +3743,7 @@ bool VIO_next_record(thread_db* tdbb,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_next_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool);
VIO_trace(DEBUG_TRACE_INFO,
@ -3790,7 +3788,7 @@ bool VIO_next_record(thread_db* tdbb,
rpb->rpb_f_page, rpb->rpb_f_line);
#endif
tdbb->bumpRelStats(RuntimeStatistics::RECORD_SEQ_READS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_SEQ_READS, rpb->rpb_relation->getId());
return true;
}
@ -3813,7 +3811,7 @@ Record* VIO_record(thread_db* tdbb, record_param* rpb, const Format* format, Mem
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE,
"VIO_record (rel_id %u, record_param %" QUADFORMAT"d, format %d, pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), format ? format->fmt_version : 0,
relation->getId(), rpb->rpb_number.getValue(), format ? format->fmt_version : 0,
(void*) pool);
#endif
@ -3856,7 +3854,7 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS,
"VIO_refetch_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
#endif
const TraNumber tid_fetch = rpb->rpb_transaction_nr;
@ -3882,7 +3880,7 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction
VIO_data(tdbb, rpb, tdbb->getDefaultPool());
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, rpb->rpb_relation->getId());
// If record is present, and the transaction is read committed,
// make sure the record has not been updated. Also, punt after
@ -3897,7 +3895,7 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction
// dimitr: reads using the undo log are also OK
!(rpb->rpb_runtime_flags & RPB_undo_read))
{
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, rpb->rpb_relation->getId());
// Cannot use Arg::Num here because transaction number is 64-bit unsigned integer
ERR_post(Arg::Gds(isc_deadlock) <<
@ -3933,7 +3931,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_store (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
")\n", relation->rel_id, rpb->rpb_number.getValue(),
")\n", relation->getId(), rpb->rpb_number.getValue(),
transaction ? transaction->tra_number : 0);
#endif
@ -3944,7 +3942,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
if (needDfw(tdbb, transaction))
{
switch ((RIDS) relation->rel_id)
switch ((RIDS) relation->getId())
{
case rel_pages:
case rel_formats:
@ -4268,7 +4266,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
}
// this should be scheduled even in database creation (system transaction)
switch ((RIDS) relation->rel_id)
switch ((RIDS) relation->getId())
{
case rel_collations:
{
@ -4310,7 +4308,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
verb_post(tdbb, transaction, rpb, 0);
}
tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->getId());
// for an autocommit transaction, mark a commit as necessary
@ -4404,7 +4402,7 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction, TraceSweepEvent* traceSwee
traceSweep->beginSweepRelation(relation);
if (gc) {
gc->sweptRelation(transaction->tra_oldest_active, relation->rel_id);
gc->sweptRelation(transaction->tra_oldest_active, relation->getId());
}
while (VIO_next_record(tdbb, &rpb, transaction, 0, DPM_next_all))
@ -4465,7 +4463,7 @@ WriteLockResult VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* t
#ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES,
"VIO_writelock (rel_id %u, org_rpb %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, org_rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), org_rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -4604,7 +4602,7 @@ WriteLockResult VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* t
if (transaction->tra_flags & TRA_autocommit)
transaction->tra_flags |= TRA_perform_autocommit;
tdbb->bumpRelStats(RuntimeStatistics::RECORD_LOCKS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_LOCKS, relation->getId());
// VIO_writelock
Database* dbb = tdbb->getDatabase();
@ -4869,7 +4867,7 @@ static void delete_record(thread_db* tdbb, record_param* rpb, ULONG prior_page,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"delete_record (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", pool %p)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page, (void*)pool);
relation->getId(), rpb->rpb_number.getValue(), prior_page, (void*)pool);
VIO_trace(DEBUG_WRITES_INFO,
" delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -4944,7 +4942,7 @@ static UCHAR* delete_tail(thread_db* tdbb,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"delete_tail (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", tail %p, length %u)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page, tail, tail_length);
relation->getId(), rpb->rpb_number.getValue(), prior_page, tail, tail_length);
VIO_trace(DEBUG_WRITES_INFO,
" tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -5043,7 +5041,7 @@ static void expunge(thread_db* tdbb, record_param* rpb, const jrd_tra* transacti
VIO_trace(DEBUG_WRITES,
"expunge (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
", prior_page %" SLONGFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
prior_page);
#endif
@ -5099,7 +5097,7 @@ static void expunge(thread_db* tdbb, record_param* rpb, const jrd_tra* transacti
RecordStack empty_staying;
garbage_collect(tdbb, &temp, rpb->rpb_page, empty_staying);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_EXPUNGES, rpb->rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_EXPUNGES, rpb->rpb_relation->getId());
}
@ -5128,7 +5126,7 @@ static void garbage_collect(thread_db* tdbb, record_param* rpb, ULONG prior_page
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES,
"garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, prior_page %" SLONGFORMAT", staying)\n",
relation->rel_id, rpb->rpb_number.getValue(), prior_page);
relation->getId(), rpb->rpb_number.getValue(), prior_page);
VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -5595,7 +5593,7 @@ static void invalidate_cursor_records(jrd_tra* transaction, record_param* mod_rp
if (org_rpb != mod_rpb &&
org_rpb->rpb_relation && org_rpb->rpb_number.isValid() &&
org_rpb->rpb_relation->rel_id == mod_rpb->rpb_relation->rel_id &&
org_rpb->rpb_relation->getId() == mod_rpb->rpb_relation->getId() &&
org_rpb->rpb_number == mod_rpb->rpb_number)
{
org_rpb->rpb_runtime_flags |= RPB_refetch;
@ -5716,7 +5714,7 @@ static void list_staying_fast(thread_db* tdbb, record_param* rpb, RecordStack& s
garbage_collect(tdbb, &temp2, temp.rpb_page, staying);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_PURGES, temp.rpb_relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_PURGES, temp.rpb_relation->getId());
if (back_rpb && back_rpb->rpb_page == page && back_rpb->rpb_line == line)
{
@ -5963,7 +5961,7 @@ static void notify_garbage_collector(thread_db* tdbb, record_param* rpb, TraNumb
const ULONG dp_sequence = rpb->rpb_number.getValue() / dbb->dbb_max_records;
const TraNumber minTranId = gc->addPage(relation->rel_id, dp_sequence, tranid);
const TraNumber minTranId = gc->addPage(relation->getId(), dp_sequence, tranid);
if (tranid > minTranId)
tranid = minTranId;
@ -6004,7 +6002,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu
VIO_trace(DEBUG_TRACE_ALL,
"prepare_update (rel_id %u, transaction %" SQUADFORMAT
", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ",
relation->rel_id, transaction ? transaction->tra_number : 0, commit_tid_read,
relation->getId(), transaction ? transaction->tra_number : 0, commit_tid_read,
rpb ? rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL,
@ -6128,7 +6126,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu
delete_record(tdbb, temp, 0, NULL);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->getId());
return PrepareResult::DELETED;
}
}
@ -6173,7 +6171,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu
if (writeLockSkipLocked.isAssigned() || (transaction->tra_flags & TRA_read_consistency))
{
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->getId());
return PrepareResult::DELETED;
}
@ -6194,7 +6192,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu
delete_record(tdbb, temp, 0, NULL);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->getId());
return PrepareResult::CONFLICT;
}
@ -6299,7 +6297,7 @@ static PrepareResult prepare_update(thread_db* tdbb, jrd_tra* transaction, TraNu
// For SNAPSHOT mode transactions raise error early
if (!(transaction->tra_flags & TRA_read_committed))
{
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->getId());
if (writeLockSkipLocked == true)
return PrepareResult::SKIP_LOCKED;
@ -6374,7 +6372,7 @@ static void protect_system_table_insert(thread_db* tdbb,
}
status_exception::raise(Arg::Gds(isc_protect_sys_tab) <<
Arg::Str("INSERT") << Arg::Str(relation->rel_name));
Arg::Str("INSERT") << Arg::Str(relation->getName()));
}
@ -6406,7 +6404,7 @@ static void protect_system_table_delupd(thread_db* tdbb,
}
status_exception::raise(Arg::Gds(isc_protect_sys_tab) <<
Arg::Str(operation) << Arg::Str(relation->rel_name));
Arg::Str(operation) << Arg::Str(relation->getName()));
}
@ -6436,7 +6434,7 @@ static void purge(thread_db* tdbb, record_param* rpb)
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL,
"purge (rel_id %u, record_param %" QUADFORMAT"d)\n",
relation->rel_id, rpb->rpb_number.getValue());
relation->getId(), rpb->rpb_number.getValue());
VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -6488,7 +6486,7 @@ static void purge(thread_db* tdbb, record_param* rpb)
staying.push(record);
garbage_collect(tdbb, &temp, rpb->rpb_page, staying);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_PURGES, relation->rel_id);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_PURGES, relation->getId());
return; // true;
}
@ -6515,7 +6513,7 @@ static void replace_record(thread_db* tdbb,
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE_ALL,
"replace_record (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT")\n",
relation->rel_id, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
relation->getId(), rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
@ -6573,7 +6571,7 @@ static void refresh_fk_fields(thread_db* tdbb, Record* old_rec, record_param* cu
for (FB_SIZE_T i = 0; i < frgnCount; i++)
{
// We need self-referenced FK's only
if ((*relation->rel_foreign_refs.frgn_relations)[i] == relation->rel_id)
if ((*relation->rel_foreign_refs.frgn_relations)[i] == relation->getId())
{
index_desc idx;
idx.idx_id = idx_invalid;
@ -6773,7 +6771,7 @@ void VIO_update_in_place(thread_db* tdbb,
VIO_trace(DEBUG_TRACE_ALL,
"update_in_place (rel_id %u, transaction %" SQUADFORMAT", org_rpb %" QUADFORMAT"d, "
"new_rpb %" QUADFORMAT"d)\n",
relation->rel_id, transaction ? transaction->tra_number : 0, org_rpb->rpb_number.getValue(),
relation->getId(), transaction ? transaction->tra_number : 0, org_rpb->rpb_number.getValue(),
new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO,