Skip to content

Commit cac4b47

Browse files
committed
Bug#36495761 PB2: ndb_restore_schema_tolerance fail sporadically creating table
2/2 Patch for 7.6 Only Context: MTR test ndb_restore_schema_tolerance fail sporadically due to an error in DBUTIL. Util has a pool of prepared operations that stores the Prepared Operations until they are executed. The pool has a fixed size of 6 where 4 are 'reserved' for some operations on special tables, so, in fact, there are only 2 available spaces in preparedOperationPoll. When UTIL handles many preperareOperation simultaneous the pool can get exhausted because it fails seize a free object in the pool to store the new prepared op. In a similar way, runningPrepares pool used by UTIL to store the running prepare operations, can also be exhausted. The pool size is 1 but there is nothing preventing TRIX/DICT to send many UTIL_PREPARE_REQ in parallel to UTIL. In that scenario UTIL will fail to seize a free object for the new running prepare operation. Problem: Test fail to create table because the prepared operation triggered by trix to build the index stats of the new table finds one the util pool exhausted. Solution: UTIL changed to distinguish between internal Prepared Operations (from TRIX) and Prepared Operation for events (from DICT). In both pools a special space for internal prepare operations is reserved, remaining space is for prepOps from DICT as before. This way we ensure that, in a scenario where UTIL is force to handle many concurrent operation the internal ones are priority and there will be always a free space in both pools for them. Change-Id: I3625e08cc29f341be6d77b5a60885af6e5f601cc
1 parent b673ec1 commit cac4b47

File tree

5 files changed

+116
-17
lines changed

5 files changed

+116
-17
lines changed

storage/ndb/include/kernel/signaldata/UtilPrepare.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2024, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -55,6 +55,7 @@ class UtilPrepareReq {
5555
*/
5656
friend class DbUtil;
5757
friend class Trix;
58+
friend class Dbdict;
5859

5960
/**
6061
* For printing
@@ -71,7 +72,7 @@ class UtilPrepareReq {
7172
Insert = 2,
7273
Delete = 3,
7374
Write = 4,
74-
Probe = 5 // check existance...
75+
Probe = 5 // check existence...
7576
};
7677

7778
enum KeyValue {
@@ -85,8 +86,10 @@ class UtilPrepareReq {
8586
ReorgInd = 8
8687
};
8788

89+
enum Flags { InternalOperation = 1 };
90+
8891
// Signal constants
89-
STATIC_CONST( SignalLength = 3 );
92+
STATIC_CONST( SignalLength = 4 );
9093
STATIC_CONST( PROPERTIES_SECTION = 0 );
9194
STATIC_CONST( NoOfSections = 1 );
9295

@@ -96,6 +99,7 @@ class UtilPrepareReq {
9699
Uint32 senderData; // MUST be no 1!
97100
Uint32 senderRef;
98101
Uint32 schemaTransId;
102+
Uint32 flags;
99103
};
100104

101105
/**

storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17894,6 +17894,7 @@ Dbdict::prepareUtilTransaction(Callback *pcallback,
1789417894

1789517895
utilPrepareReq->setSenderRef(reference());
1789617896
utilPrepareReq->setSenderData(senderData);
17897+
utilPrepareReq->flags = 0;
1789717898

1789817899
const Uint32 pageSizeInWords = 128;
1789917900
Uint32 propPage[pageSizeInWords];

storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ void
143143
DbUtil::releasePrepare(PreparePtr prepPtr) {
144144
prepPtr.p->preparePages.release();
145145
c_runningPrepares.release(prepPtr); // Automatic release in pool
146+
if (prepPtr.p->internalFlag) {
147+
c_freeInternalRunningPrepares++;
148+
prepPtr.p->internalFlag = false;
149+
}
146150
}
147151

148152
void
@@ -152,6 +156,10 @@ DbUtil::releasePreparedOperation(PreparedOperationPtr prepOpPtr) {
152156
prepOpPtr.p->rsInfo.release();
153157
prepOpPtr.p->pkBitmask.clear();
154158
c_preparedOperationPool.release(prepOpPtr); // No list holding these structs
159+
if (prepOpPtr.p->internalFlag) {
160+
c_freeInternalPreparedOps++;
161+
prepOpPtr.p->internalFlag = false;
162+
}
155163
}
156164

157165
void
@@ -192,6 +200,27 @@ DbUtil::execREAD_CONFIG_REQ(Signal* signal)
192200
ndbrequire(p != 0);
193201

194202
{
203+
/**
204+
* UTIL_PREPARE_REQ can be send by client blocks
205+
* to create a PreparedOperation template in DBUTIL
206+
* which can later be used by one or more
207+
* UTIL_EXECUTE_REQ signals to define and execute
208+
* one or more operations in a transaction, one
209+
* or more times before releasing the prepared
210+
* operations with UTIL_RELEASE_REQ
211+
*
212+
* UTIL_PREPARE_REQ allocates a Prepare(Request) record
213+
* for the duration of the PREPARE_REQ.
214+
* UTIL_PREPARE_REQ allocates a PreparedOperation record
215+
* for the duration of the PreparedOperation existing
216+
* (until UTIL_RELEASE_REQ)
217+
*
218+
* UTIL_PREPARE_REQ requests can be marked as
219+
* internal, in which case they can use a reserved
220+
* pool of Prepare and PreparedOperation records to
221+
* avoid concurrent non-internal requests starving
222+
* them.
223+
*/
195224
/* ** Dimensioning inputs : */
196225
Uint32 maxUIBuildBatchSize = 64;
197226
ndb_mgm_get_int_parameter(p, CFG_DB_UI_BUILD_MAX_BATCHSIZE,
@@ -207,8 +236,20 @@ DbUtil::execREAD_CONFIG_REQ(Signal* signal)
207236

208237
/* Based on existing setting, probably excessive */
209238
const Uint32 MaxNonSchemaBuildOps = 48;
210-
const Uint32 MaxPreparedOps = 6; // three hardcoded, one for setval, two for test
211-
const Uint32 NumConcurrentPrepares = 1; /* One parallel prepare */
239+
240+
// 4 hardcoded and defined at startup, 1 internal 1 for api events
241+
const Uint32 HardcodedOps = 4; /* SEQUENCE Service */
242+
const Uint32 MaxInternalPreparedOps = 1; /* TRIX ops - serialised */
243+
const Uint32 MaxExternalPreparedOps = 1; /* DICT Event ops */
244+
const Uint32 MaxPreparedOps =
245+
HardcodedOps + MaxInternalPreparedOps + MaxExternalPreparedOps;
246+
247+
const Uint32 MaxInternalConcurrentPrepares =
248+
MaxInternalPreparedOps; /* TRIX ops */
249+
const Uint32 MaxExternalConcurrentPrepares =
250+
MaxExternalPreparedOps; /* DICT Event ops */
251+
const Uint32 NumConcurrentPrepares =
252+
MaxInternalConcurrentPrepares + MaxExternalConcurrentPrepares;
212253

213254
const Uint32 SparePages = 5; /* Arbitrary */
214255
const Uint32 PagesPerPreparingOp = 5; /* Arbitrary */
@@ -281,8 +322,11 @@ DbUtil::execREAD_CONFIG_REQ(Signal* signal)
281322
ndbout_c(" DataBuffWordsPerOp : %u", DataBuffWordsPerOp);
282323
ndbout_c(" numDataBuffers : %u", numDataBuffers);
283324
ndbout_c(" numPages : %u", numPages);
325+
ndbout_c(" MaxInternalPreparedOps : %u", MaxInternalPreparedOps);
326+
ndbout_c(" MaxInternalConcurrentPrepares : %u",
327+
MaxInternalConcurrentPrepares);
284328
}
285-
329+
286330

287331
/* ** Settings */
288332

@@ -293,6 +337,9 @@ DbUtil::execREAD_CONFIG_REQ(Signal* signal)
293337
c_transactionPool.setSize(MaxConcurrentTrans);
294338
c_attrMappingPool.setSize(MaxAttributeMappings);
295339
c_dataBufPool.setSize(numDataBuffers);
340+
341+
c_freeInternalPreparedOps = MaxInternalPreparedOps;
342+
c_freeInternalRunningPrepares = MaxInternalConcurrentPrepares;
296343
}
297344

298345
{
@@ -1106,6 +1153,7 @@ DbUtil::execUTIL_PREPARE_REQ(Signal* signal)
11061153
const Uint32 senderRef = req->senderRef;
11071154
const Uint32 senderData = req->senderData;
11081155
const Uint32 schemaTransId= req->schemaTransId;
1156+
const Uint32 flags = req->flags;
11091157

11101158
if(signal->getNoOfSections() == 0) {
11111159
// Missing prepare data
@@ -1131,8 +1179,16 @@ DbUtil::execUTIL_PREPARE_REQ(Signal* signal)
11311179
senderRef, senderData);
11321180
return;
11331181
}
1134-
if (!c_runningPrepares.seizeFirst(prepPtr))
1135-
{
1182+
1183+
const bool internalPrepOp = flags & UtilPrepareReq::InternalOperation;
1184+
ndbassert(c_runningPrepares.getPool().getNoOfFree() >=
1185+
c_freeInternalRunningPrepares);
1186+
const Uint32 freePrepares =
1187+
(internalPrepOp ? c_freeInternalRunningPrepares
1188+
: c_runningPrepares.getPool().getNoOfFree() -
1189+
c_freeInternalRunningPrepares);
1190+
1191+
if (freePrepares == 0) {
11361192
jam();
11371193
releaseSections(handle);
11381194
sendUtilPrepareRef(signal, UtilPrepareRef::PREPARE_SEIZE_ERROR,
@@ -1142,8 +1198,17 @@ DbUtil::execUTIL_PREPARE_REQ(Signal* signal)
11421198
ndbrequire(false);
11431199
}
11441200
return;
1145-
};
1146-
handle.getSection(ptr, UtilPrepareReq::PROPERTIES_SECTION);
1201+
}
1202+
1203+
jam();
1204+
ndbrequire(c_runningPrepares.seizeFirst(prepPtr));
1205+
if (internalPrepOp) {
1206+
jam();
1207+
ndbrequire(c_freeInternalRunningPrepares > 0);
1208+
c_freeInternalRunningPrepares--;
1209+
prepPtr.p->internalFlag = true;
1210+
}
1211+
ndbrequire(handle.getSection(ptr, UtilPrepareReq::PROPERTIES_SECTION));
11471212
const Uint32 noPages = (ptr.sz + sizeof(Page32)) / sizeof(Page32);
11481213
ndbassert(noPages > 0);
11491214
if (!prepPtr.p->preparePages.seize(noPages)) {
@@ -1354,7 +1419,13 @@ DbUtil::prepareOperation(Signal* signal,
13541419
* Seize and store PreparedOperation struct
13551420
*******************************************/
13561421
PreparedOperationPtr prepOpPtr;
1357-
if(!c_preparedOperationPool.seize(prepOpPtr)) {
1422+
const bool internalPrepOp = prepPtr.p->internalFlag;
1423+
ndbassert(c_preparedOperationPool.getNoOfFree() >= c_freeInternalPreparedOps);
1424+
const Uint32 freePrepares =
1425+
(internalPrepOp
1426+
? c_freeInternalPreparedOps
1427+
: c_preparedOperationPool.getNoOfFree() - c_freeInternalPreparedOps);
1428+
if (freePrepares == 0) {
13581429
jam();
13591430
sendUtilPrepareRef(signal, UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR,
13601431
prepPtr.p->clientRef, prepPtr.p->clientData);
@@ -1365,7 +1436,15 @@ DbUtil::prepareOperation(Signal* signal,
13651436
}
13661437
return;
13671438
}
1439+
ndbrequire(c_preparedOperationPool.seize(prepOpPtr));
1440+
if (internalPrepOp) {
1441+
jam();
1442+
ndbrequire(c_freeInternalPreparedOps > 0);
1443+
c_freeInternalPreparedOps--;
1444+
prepOpPtr.p->internalFlag = true;
1445+
}
13681446
prepPtr.p->prepOpPtr = prepOpPtr;
1447+
ndbrequire(prepPtr.p->internalFlag == prepOpPtr.p->internalFlag);
13691448

13701449
/********************
13711450
* Read request info

storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2024, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -178,13 +178,15 @@ class DbUtil : public SimulatedBlock
178178
* information.
179179
*/
180180
struct Prepare {
181-
Prepare(Page32_pool & ap) : preparePages(ap) {}
181+
Prepare(Page32_pool &ap) : internalFlag(false), preparePages(ap) {}
182182

183183
/*** Client info ***/
184184
Uint32 clientRef;
185185
Uint32 clientData;
186186
Uint32 schemaTransId;
187187

188+
bool internalFlag; // flag if operation is internal
189+
188190
/**
189191
* SimpleProp sent in UTIL_PREPARE_REQ
190192
*
@@ -227,9 +229,12 @@ class DbUtil : public SimulatedBlock
227229
struct PreparedOperation {
228230
PreparedOperation(AttrMappingBuffer::DataBufferPool & am,
229231
AttrInfoBuffer::DataBufferPool & ai,
230-
ResultSetInfoBuffer::DataBufferPool & rs) :
231-
releaseFlag(false), attrMapping(am), attrInfo(ai), rsInfo(rs)
232-
{
232+
ResultSetInfoBuffer::DataBufferPool &rs)
233+
: releaseFlag(false),
234+
internalFlag(false),
235+
attrMapping(am),
236+
attrInfo(ai),
237+
rsInfo(rs) {
233238
pkBitmask.clear();
234239
}
235240

@@ -240,6 +245,7 @@ class DbUtil : public SimulatedBlock
240245
bool releaseFlag; // flag if operation release after completion
241246
UtilPrepareReq::OperationTypeValue operationType;
242247

248+
bool internalFlag; // flag if operation is internal
243249
/**
244250
* Attribute Mapping
245251
*
@@ -419,8 +425,13 @@ class DbUtil : public SimulatedBlock
419425
PreparedOperation_pool c_preparedOperationPool;
420426
Transaction_pool c_transactionPool;
421427

428+
Uint32 c_freeInternalPreparedOps;
429+
430+
Uint32 c_freeInternalRunningPrepares;
431+
422432
DataBuffer<1,ArrayPool<DataBufferSegment<1> > >::DataBufferPool c_attrMappingPool;
423433
DataBuffer<11,ArrayPool<DataBufferSegment<11> > >::DataBufferPool c_dataBufPool;
434+
424435
Prepare_dllist c_runningPrepares;
425436
Transaction_dllist c_seizingTransactions; // Being seized at TC
426437
Transaction_dllist c_runningTransactions; // Seized and now exec.

storage/ndb/src/kernel/blocks/trix/Trix.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2022, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2024, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -1144,6 +1144,7 @@ void Trix::prepareInsertTransactions(Signal* signal,
11441144
utilPrepareReq->senderRef = reference();
11451145
utilPrepareReq->senderData = subRecPtr.i;
11461146
utilPrepareReq->schemaTransId = subRec->schemaTransId;
1147+
utilPrepareReq->flags = UtilPrepareReq::InternalOperation;
11471148

11481149
const Uint32 pageSizeInWords = 128;
11491150
Uint32 propPage[pageSizeInWords];
@@ -1648,6 +1649,7 @@ Trix::execCOPY_DATA_IMPL_REQ(Signal* signal)
16481649
utilPrepareReq->senderRef = reference();
16491650
utilPrepareReq->senderData = subRecPtr.i;
16501651
utilPrepareReq->schemaTransId = subRec->schemaTransId;
1652+
utilPrepareReq->flags = UtilPrepareReq::InternalOperation;
16511653

16521654
const Uint32 pageSizeInWords = 128;
16531655
Uint32 propPage[pageSizeInWords];
@@ -1770,6 +1772,7 @@ Trix::execBUILD_FK_IMPL_REQ(Signal* signal)
17701772
utilPrepareReq->senderRef = reference();
17711773
utilPrepareReq->senderData = subRecPtr.i;
17721774
utilPrepareReq->schemaTransId = subRec->schemaTransId;
1775+
utilPrepareReq->flags = UtilPrepareReq::InternalOperation;
17731776

17741777
const Uint32 pageSizeInWords = 128;
17751778
Uint32 propPage[pageSizeInWords];
@@ -3085,6 +3088,7 @@ Trix::statSendPrepare(Signal* signal, StatOp& stat)
30853088
utilReq->senderData = stat.m_ownPtrI;
30863089
utilReq->senderRef = reference();
30873090
utilReq->schemaTransId = req->transId;
3091+
utilReq->flags = UtilPrepareReq::InternalOperation;
30883092

30893093
Uint32 wbuf[256];
30903094
LinearWriter w(&wbuf[0], sizeof(wbuf) >> 2);

0 commit comments

Comments
 (0)