Skip to content

Commit 3f2f549

Browse files
committed
Carefully watch for cache version
1 parent 6c85965 commit 3f2f549

File tree

4 files changed

+88
-20
lines changed

4 files changed

+88
-20
lines changed

src/jrd/CacheVector.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,22 @@ ULONG* TransactionNumber::getFlags(thread_db* tdbb)
7272
}
7373

7474

75-
// class VersionSupport
75+
// class VersionIncr
7676

77-
MdcVersion VersionSupport::next(thread_db* tdbb)
77+
VersionIncr::VersionIncr(thread_db* tdbb)
78+
: mdc(MetadataCache::get(tdbb))
7879
{
79-
return MetadataCache::get(tdbb)->nextVersion();
80+
current = ++(mdc->mdc_front);
81+
}
82+
83+
VersionIncr::~VersionIncr()
84+
{
85+
++(mdc->mdc_back);
86+
}
87+
88+
MdcVersion VersionIncr::getVersion()
89+
{
90+
return current;
8091
}
8192

8293

src/jrd/CacheVector.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace Jrd {
4444

4545
class thread_db;
4646
class Lock;
47+
class MetadataCache;
4748
enum lck_t : UCHAR;
4849

4950
class ObjectBase
@@ -120,10 +121,18 @@ namespace CacheFlag
120121
}
121122

122123

123-
class VersionSupport
124+
// Controls growth of from & back values in metadata cache
125+
126+
class VersionIncr
124127
{
125128
public:
126-
static MdcVersion next(thread_db* tdbb);
129+
VersionIncr(thread_db* tdbb);
130+
~VersionIncr();
131+
MdcVersion getVersion();
132+
133+
private:
134+
MetadataCache* mdc;
135+
MdcVersion current;
127136
};
128137

129138

@@ -344,18 +353,25 @@ class ListEntry : public HazardObject
344353

345354
// RETIRED is set here to avoid illegal gc until traNumber correction
346355
auto newFlags = flags | CacheFlag::COMMITTED | CacheFlag::RETIRED;
356+
347357
// NOCOMMIT cleared to avoid extra ASTs
348358
newFlags &= ~CacheFlag::NOCOMMIT;
359+
360+
// Handle front & back of MDC
361+
VersionIncr incr(tdbb);
362+
363+
// And finally try to make object version world-visible
349364
if (cacheFlags.compare_exchange_weak(flags, newFlags,
350365
atomics::memory_order_release, atomics::memory_order_acquire))
351366
{
367+
traNumber = nextTrans;
368+
version = incr.getVersion();
369+
cacheFlags &= ~CacheFlag::RETIRED; // Enable GC
370+
352371
break;
353372
}
354373
}
355374

356-
traNumber = nextTrans;
357-
version = VersionSupport::next(tdbb);
358-
cacheFlags &= ~CacheFlag::RETIRED; // Enable GC
359375

360376
return flags;
361377
}

src/jrd/Statement.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,9 @@ Statement::Statement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
205205

206206
void Statement::loadResources(thread_db* tdbb, Request* req, bool withLock)
207207
{
208-
const MdcVersion currentMdcVersion = MetadataCache::get(tdbb)->getVersion();
209-
if ((!latestVer) || (latestVer->version != currentMdcVersion))
208+
auto* mdc = MetadataCache::get(tdbb);
209+
const MdcVersion backVersion = mdc->getBackVersion();
210+
if ((!latestVer) || (latestVer->version != backVersion))
210211
{
211212
MutexEnsureUnlock guard(lvMutex, FB_FUNCTION);
212213

@@ -216,8 +217,10 @@ void Statement::loadResources(thread_db* tdbb, Request* req, bool withLock)
216217
guard.enter();
217218
}
218219

219-
if ((!withLock) || (latestVer->version != currentMdcVersion))
220+
if ((!latestVer) || (latestVer->version != backVersion))
220221
{
222+
for(MetadataCache::StableVersion sv(mdc); sv; sv.next())
223+
{
221224
// Also check for changed streams from known sources
222225
if (withLock && !streamsFormatCompare(tdbb))
223226
ERR_post(Arg::Gds(isc_random) << "Statement format outdated, need to be reprepared");
@@ -227,8 +230,9 @@ void Statement::loadResources(thread_db* tdbb, Request* req, bool withLock)
227230
resources->charSets.getCount() + resources->relations.getCount() + resources->procedures.getCount() +
228231
resources->functions.getCount() + resources->triggers.getCount();
229232

230-
latestVer = FB_NEW_RPT(*pool, resourceCount) VersionedObjects(resourceCount, currentMdcVersion);
233+
latestVer = FB_NEW_RPT(*pool, resourceCount) VersionedObjects(resourceCount, sv.getBackVersion());
231234
resources->transfer(tdbb, latestVer, flags & FLAG_INTERNAL);
235+
}
232236
}
233237
}
234238

src/jrd/met.h

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ inline constexpr int TFB_array = 2;
102102

103103
namespace Jrd {
104104

105+
// Forward decl
106+
107+
class VersionIncr;
108+
105109
// Procedure block
106110

107111
class jrd_prc : public Routine
@@ -233,7 +237,6 @@ class MetadataCache : public Firebird::PermanentStorage
233237
mdc_procedures(getPool()),
234238
mdc_functions(getPool()),
235239
mdc_charsets(getPool()),
236-
mdc_version(0),
237240
mdc_cleanup_queue(pool)
238241
{
239242
memset(mdc_triggers, 0, sizeof(mdc_triggers));
@@ -336,15 +339,46 @@ class MetadataCache : public Firebird::PermanentStorage
336339
static void release_temp_tables(thread_db* tdbb, jrd_tra* transaction);
337340
static void retain_temp_tables(thread_db* tdbb, jrd_tra* transaction, TraNumber new_number);
338341

339-
MdcVersion getVersion()
342+
// Is used to check for comleted changes in metadata cache since some previous moment
343+
MdcVersion getBackVersion()
340344
{
341-
return mdc_version.load(std::memory_order_relaxed);
345+
return mdc_back.load(std::memory_order_relaxed);
342346
}
343347

344-
MdcVersion nextVersion()
348+
// Checks for version's drift during resources load for request(s)
349+
friend class StableVersion;
350+
class StableVersion
345351
{
346-
return ++mdc_version;
347-
}
352+
public:
353+
StableVersion(MetadataCache* mdc)
354+
: mdc(mdc), back(mdc->mdc_back), front(back + 1)
355+
{ }
356+
357+
operator bool()
358+
{
359+
if (front == back)
360+
return false;
361+
back = mdc->mdc_back;
362+
return true;
363+
}
364+
365+
void next()
366+
{
367+
front = mdc->mdc_front;
368+
}
369+
370+
MdcVersion getBackVersion()
371+
{
372+
return back;
373+
}
374+
375+
private:
376+
MetadataCache* mdc;
377+
MdcVersion back, front;
378+
};
379+
380+
// In CacheVector.h
381+
friend class VersionIncr;
348382

349383
SLONG lookupSequence(thread_db*, const QualifiedName& genName)
350384
{
@@ -541,8 +575,11 @@ class MetadataCache : public Firebird::PermanentStorage
541575
CacheVector<Cached::Function> mdc_functions; // User defined functions
542576
CacheVector<Cached::CharSet> mdc_charsets; // intl character set descriptions
543577
TriggersSet mdc_triggers[DB_TRIGGERS_COUNT];
544-
545-
std::atomic<MdcVersion> mdc_version; // Current version of metadata cache (should have 2 nums !!!!!!!!!!!!!!!)
578+
// Two numbers are required because commit into cache is not atomic event.
579+
// Front value is incremented before commit, back - after commit.
580+
// To ensure cache remained in stable state compare
581+
// back before action to protect and front after it.
582+
std::atomic<MdcVersion> mdc_front = 0, mdc_back = 0;
546583
CleanupQueue mdc_cleanup_queue;
547584
};
548585

0 commit comments

Comments
 (0)