Skip to content

Commit a6bf341

Browse files
authored
Add missing synchronization to cached vectors of known pages (#8069)
* Add missing synchronization to cached vectors of known pages. Thanks to Vlad Khorsun. * Fixed typo
1 parent e93f6ae commit a6bf341

File tree

6 files changed

+126
-47
lines changed

6 files changed

+126
-47
lines changed

src/jrd/Database.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,65 @@ namespace Jrd
468468
dbb_filename, dbb_config));
469469
}
470470

471+
// Methods encapsulating operations with vectors of known pages
472+
473+
ULONG Database::getKnownPagesCount(SCHAR ptype)
474+
{
475+
fb_assert(ptype == pag_transactions || ptype == pag_ids);
476+
477+
SyncLockGuard guard(&dbb_pages_sync, SYNC_SHARED, FB_FUNCTION);
478+
479+
const auto vector =
480+
(ptype == pag_transactions) ? dbb_tip_pages :
481+
(ptype == pag_ids) ? dbb_gen_pages :
482+
nullptr;
483+
484+
return vector ? (ULONG) vector->count() : 0;
485+
}
486+
487+
ULONG Database::getKnownPage(SCHAR ptype, ULONG sequence)
488+
{
489+
fb_assert(ptype == pag_transactions || ptype == pag_ids);
490+
491+
SyncLockGuard guard(&dbb_pages_sync, SYNC_SHARED, FB_FUNCTION);
492+
493+
const auto vector =
494+
(ptype == pag_transactions) ? dbb_tip_pages :
495+
(ptype == pag_ids) ? dbb_gen_pages :
496+
nullptr;
497+
498+
if (!vector || sequence >= vector->count())
499+
return 0;
500+
501+
return (*vector)[sequence];
502+
}
503+
504+
void Database::setKnownPage(SCHAR ptype, ULONG sequence, ULONG value)
505+
{
506+
fb_assert(ptype == pag_transactions || ptype == pag_ids);
507+
508+
SyncLockGuard guard(&dbb_pages_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
509+
510+
auto& rvector = (ptype == pag_transactions) ? dbb_tip_pages : dbb_gen_pages;
511+
512+
rvector = vcl::newVector(*dbb_permanent, rvector, sequence + 1);
513+
514+
(*rvector)[sequence] = value;
515+
}
516+
517+
void Database::copyKnownPages(SCHAR ptype, ULONG count, ULONG* data)
518+
{
519+
fb_assert(ptype == pag_transactions || ptype == pag_ids);
520+
521+
SyncLockGuard guard(&dbb_pages_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
522+
523+
auto& rvector = (ptype == pag_transactions) ? dbb_tip_pages : dbb_gen_pages;
524+
525+
rvector = vcl::newVector(*dbb_permanent, rvector, count);
526+
527+
memcpy(rvector->memPtr(), data, count * sizeof(ULONG));
528+
}
529+
471530
// Database::Linger class implementation
472531

473532
void Database::Linger::handler()

src/jrd/Database.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,6 @@ class Database : public pool_alloc<type_dbb>
451451

452452
Lock* dbb_retaining_lock; // lock for preserving commit retaining snapshot
453453
PageManager dbb_page_manager;
454-
vcl* dbb_t_pages; // pages number for transactions
455-
vcl* dbb_gen_id_pages; // known pages for gen_id
456454
BlobFilter* dbb_blob_filters; // known blob filters
457455

458456
MonitoringData* dbb_monitoring_data; // monitoring data
@@ -463,6 +461,10 @@ class Database : public pool_alloc<type_dbb>
463461
Firebird::SyncObject dbb_modules_sync;
464462
DatabaseModules dbb_modules; // external function/filter modules
465463

464+
// Vectors of known pages and their synchronization
465+
Firebird::SyncObject dbb_pages_sync; // guard access to dbb_XXX_pages vectors
466+
vcl* dbb_tip_pages; // known TIP pages
467+
vcl* dbb_gen_pages; // known generator pages
466468
public:
467469
Firebird::AutoPtr<ExtEngineManager> dbb_extManager; // external engine manager
468470

@@ -589,6 +591,12 @@ class Database : public pool_alloc<type_dbb>
589591
return ENCODE_ODS(dbb_ods_version, dbb_minor_version);
590592
}
591593

594+
// Methods encapsulating operations with vectors of known pages
595+
ULONG getKnownPagesCount(SCHAR ptype);
596+
ULONG getKnownPage(SCHAR ptype, ULONG sequence);
597+
void setKnownPage(SCHAR ptype, ULONG sequence, ULONG value);
598+
void copyKnownPages(SCHAR ptype, ULONG count, ULONG* data);
599+
592600
private:
593601
Database(MemoryPool* p, Firebird::IPluginConfig* pConf, bool shared)
594602
: dbb_permanent(p),

src/jrd/dpm.epp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,26 +1355,27 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val)
13551355
const USHORT offset = generator % dbb->dbb_page_manager.gensPerPage;
13561356

13571357
WIN window(DB_PAGE_SPACE, -1);
1358-
vcl* vector = dbb->dbb_gen_id_pages;
1359-
if (!vector || (sequence >= vector->count()) || !((*vector)[sequence]))
1358+
ULONG pageNumber = dbb->getKnownPage(pag_ids, sequence);
1359+
if (!pageNumber)
13601360
{
13611361
DPM_scan_pages(tdbb);
1362-
if (!(vector = dbb->dbb_gen_id_pages) ||
1363-
(sequence >= vector->count()) || !((*vector)[sequence]))
1362+
1363+
pageNumber = dbb->getKnownPage(pag_ids, sequence);
1364+
if (!pageNumber)
13641365
{
13651366
generator_page* page = (generator_page*) DPM_allocate(tdbb, &window);
13661367
page->gpg_header.pag_type = pag_ids;
13671368
page->gpg_sequence = sequence;
13681369
CCH_must_write(tdbb, &window);
13691370
CCH_RELEASE(tdbb, &window);
1370-
DPM_pages(tdbb, 0, pag_ids, (ULONG) sequence, window.win_page.getPageNum());
1371-
vector = dbb->dbb_gen_id_pages =
1372-
vcl::newVector(*dbb->dbb_permanent, dbb->dbb_gen_id_pages, sequence + 1);
1373-
(*vector)[sequence] = window.win_page.getPageNum();
1371+
1372+
pageNumber = window.win_page.getPageNum();
1373+
dbb->setKnownPage(pag_ids, sequence, pageNumber);
1374+
DPM_pages(tdbb, 0, pag_ids, sequence, pageNumber);
13741375
}
13751376
}
13761377

1377-
window.win_page = (*vector)[sequence];
1378+
window.win_page = pageNumber;
13781379
window.win_flags = 0;
13791380

13801381
// As a special exception that allows physical backups for read-only replicas,
@@ -2041,40 +2042,49 @@ void DPM_scan_pages( thread_db* tdbb)
20412042

20422043
CCH_RELEASE(tdbb, &window);
20432044

2045+
HalfStaticArray<ULONG, 256> tipSeqList;
2046+
HalfStaticArray<ULONG, 4> genSeqList;
2047+
20442048
AutoCacheRequest request(tdbb, irq_r_pages, IRQ_REQUESTS);
20452049

20462050
FOR(REQUEST_HANDLE request) X IN RDB$PAGES
20472051
{
20482052
relation = MET_relation(tdbb, X.RDB$RELATION_ID);
20492053
relPages = relation->getBasePages();
20502054
sequence = X.RDB$PAGE_SEQUENCE;
2051-
MemoryPool* pool = dbb->dbb_permanent;
2055+
20522056
switch (X.RDB$PAGE_TYPE)
20532057
{
20542058
case pag_root:
20552059
relPages->rel_index_root = X.RDB$PAGE_NUMBER;
2056-
continue;
2060+
break;
20572061

20582062
case pag_pointer:
2059-
address = &relPages->rel_pages;
2060-
pool = relation->rel_pool;
2063+
relPages->rel_pages = vcl::newVector(*relation->rel_pool, relPages->rel_pages, sequence + 1);
2064+
(*relPages->rel_pages)[sequence] = X.RDB$PAGE_NUMBER;
20612065
break;
20622066

20632067
case pag_transactions:
2064-
address = &dbb->dbb_t_pages;
2068+
tipSeqList.resize(sequence + 1);
2069+
tipSeqList[sequence] = X.RDB$PAGE_NUMBER;
20652070
break;
20662071

20672072
case pag_ids:
2068-
address = &dbb->dbb_gen_id_pages;
2073+
genSeqList.resize(sequence + 1);
2074+
genSeqList[sequence] = X.RDB$PAGE_NUMBER;
20692075
break;
20702076

20712077
default:
20722078
CORRUPT(257); // msg 257 bad record in RDB$PAGES
20732079
}
2074-
vector = *address = vcl::newVector(*pool, *address, sequence + 1);
2075-
(*vector)[sequence] = X.RDB$PAGE_NUMBER;
20762080
}
20772081
END_FOR
2082+
2083+
if (const auto count = tipSeqList.getCount())
2084+
dbb->copyKnownPages(pag_transactions, count, tipSeqList.begin());
2085+
2086+
if (const auto count = genSeqList.getCount())
2087+
dbb->copyKnownPages(pag_ids, count, genSeqList.begin());
20782088
}
20792089

20802090

src/jrd/jrd.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3140,7 +3140,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
31403140
INI_format(tdbb, options.dpb_set_db_charset);
31413141

31423142
// If we have not allocated first TIP page, do it now.
3143-
if (!dbb->dbb_t_pages || !dbb->dbb_t_pages->count())
3143+
if (!dbb->getKnownPagesCount(pag_transactions))
31443144
TRA_extend_tip(tdbb, 0);
31453145

31463146
// There is no point to move database online at database creation since it is online by default.

src/jrd/tra.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -589,24 +589,24 @@ void TRA_extend_tip(thread_db* tdbb, ULONG sequence) //, WIN* precedence_window)
589589
CCH_must_write(tdbb, &window);
590590
CCH_RELEASE(tdbb, &window);
591591

592+
const ULONG pageNumber = window.win_page.getPageNum();
593+
592594
// Release prior page
593595

594596
if (sequence)
595597
{
596598
CCH_MARK_MUST_WRITE(tdbb, &prior_window);
597-
prior_tip->tip_next = window.win_page.getPageNum();
599+
prior_tip->tip_next = pageNumber;
598600
CCH_RELEASE(tdbb, &prior_window);
599601
}
600602

601603
// Link into internal data structures
602604

603-
vcl* vector = dbb->dbb_t_pages =
604-
vcl::newVector(*dbb->dbb_permanent, dbb->dbb_t_pages, sequence + 1);
605-
(*vector)[sequence] = window.win_page.getPageNum();
605+
dbb->setKnownPage(pag_transactions, sequence, pageNumber);
606606

607607
// Write into pages relation
608608

609-
DPM_pages(tdbb, 0, pag_transactions, sequence, window.win_page.getPageNum());
609+
DPM_pages(tdbb, 0, pag_transactions, sequence, pageNumber);
610610
}
611611

612612

@@ -2378,19 +2378,21 @@ static ULONG inventory_page(thread_db* tdbb, ULONG sequence)
23782378
Database* dbb = tdbb->getDatabase();
23792379
CHECK_DBB(dbb);
23802380

2381-
WIN window(DB_PAGE_SPACE, -1);
2382-
vcl* vector = dbb->dbb_t_pages;
2383-
while (!vector || sequence >= vector->count())
2381+
if (const ULONG pageno = dbb->getKnownPage(pag_transactions, sequence))
2382+
return pageno;
2383+
2384+
while (sequence >= dbb->getKnownPagesCount(pag_transactions))
23842385
{
23852386
DPM_scan_pages(tdbb);
23862387

2387-
if ((vector = dbb->dbb_t_pages) && sequence < vector->count())
2388+
const ULONG tipCount = dbb->getKnownPagesCount(pag_transactions);
2389+
if (sequence < tipCount)
23882390
break;
23892391

2390-
if (!vector)
2392+
if (!tipCount)
23912393
BUGCHECK(165); // msg 165 cannot find tip page
23922394

2393-
window.win_page = (*vector)[vector->count() - 1];
2395+
WIN window(DB_PAGE_SPACE, dbb->getKnownPage(pag_transactions, tipCount - 1));
23942396
tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_transactions);
23952397
const ULONG next = tip->tip_next;
23962398
CCH_RELEASE(tdbb, &window);
@@ -2400,10 +2402,10 @@ static ULONG inventory_page(thread_db* tdbb, ULONG sequence)
24002402
// Type check it
24012403
tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_transactions);
24022404
CCH_RELEASE(tdbb, &window);
2403-
DPM_pages(tdbb, 0, pag_transactions, vector->count(), window.win_page.getPageNum());
2405+
DPM_pages(tdbb, 0, pag_transactions, tipCount, window.win_page.getPageNum());
24042406
}
24052407

2406-
return (*vector)[sequence];
2408+
return dbb->getKnownPage(pag_transactions, sequence);
24072409
}
24082410

24092411

src/jrd/validation.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,21 +1937,19 @@ void Validation::walk_generators()
19371937

19381938
WIN window(DB_PAGE_SPACE, -1);
19391939

1940-
vcl* vector = dbb->dbb_gen_id_pages;
1941-
if (vector)
1940+
if (const auto idsCount = dbb->getKnownPagesCount(pag_ids))
19421941
{
1943-
vcl::iterator ptr, end;
1944-
for (ptr = vector->begin(), end = vector->end(); ptr < end; ++ptr)
1942+
for (ULONG sequence = 0; sequence < idsCount; sequence++)
19451943
{
1946-
if (*ptr)
1944+
if (const auto pageNumber = dbb->getKnownPage(pag_ids, sequence))
19471945
{
19481946
#ifdef DEBUG_VAL_VERBOSE
19491947
if (VAL_debug_level)
1950-
fprintf(stdout, "walk_generator: page %d\n", *ptr);
1948+
fprintf(stdout, "walk_generator: page %d\n", pageNumber);
19511949
#endif
19521950
// It doesn't make a difference generator_page or pointer_page because it's not used.
19531951
generator_page* page = NULL;
1954-
fetch_page(true, *ptr, pag_ids, &window, &page);
1952+
fetch_page(true, pageNumber, pag_ids, &window, &page);
19551953
release_page(&window);
19561954
}
19571955
}
@@ -3276,34 +3274,36 @@ Validation::RTN Validation::walk_tip(TraNumber transaction)
32763274
**************************************/
32773275
Database* dbb = vdr_tdbb->getDatabase();
32783276

3279-
const vcl* vector = dbb->dbb_t_pages;
3280-
if (!vector)
3277+
if (!dbb->getKnownPagesCount(pag_transactions))
32813278
return corrupt(VAL_TIP_LOST, 0);
32823279

32833280
tx_inv_page* page = 0;
32843281
const ULONG pages = transaction / dbb->dbb_page_manager.transPerTIP;
32853282

32863283
for (ULONG sequence = 0; sequence <= pages; sequence++)
32873284
{
3288-
if (!(*vector)[sequence] || sequence >= vector->count())
3285+
auto pageNumber = dbb->getKnownPage(pag_transactions, sequence);
3286+
if (!pageNumber)
32893287
{
32903288
corrupt(VAL_TIP_LOST_SEQUENCE, 0, sequence);
32913289
if (!(vdr_flags & VDR_repair))
32923290
continue;
32933291

32943292
TRA_extend_tip(vdr_tdbb, sequence);
3295-
vector = dbb->dbb_t_pages;
32963293
vdr_fixed++;
3294+
3295+
pageNumber = dbb->getKnownPage(pag_transactions, sequence);
32973296
}
32983297

32993298
WIN window(DB_PAGE_SPACE, -1);
3300-
fetch_page(true, (*vector)[sequence], pag_transactions, &window, &page);
3299+
fetch_page(true, pageNumber, pag_transactions, &window, &page);
33013300

33023301
#ifdef DEBUG_VAL_VERBOSE
33033302
if (VAL_debug_level)
3304-
fprintf(stdout, "walk_tip: page %d next %d\n", (*vector)[sequence], page->tip_next);
3303+
fprintf(stdout, "walk_tip: page %d next %d\n", pageNumber, page->tip_next);
33053304
#endif
3306-
if (page->tip_next && page->tip_next != (*vector)[sequence + 1])
3305+
const auto next = dbb->getKnownPage(pag_transactions, sequence + 1);
3306+
if (page->tip_next && page->tip_next != next)
33073307
{
33083308
corrupt(VAL_TIP_CONFUSED, 0, sequence);
33093309
}

0 commit comments

Comments
 (0)