@@ -37,6 +37,7 @@ namespace aql {
37
37
class AqlItemBlockManager ;
38
38
class BlockCollector ;
39
39
class SharedAqlItemBlockPtr ;
40
+ enum class SerializationFormat ;
40
41
41
42
// an <AqlItemBlock> is a <nrItems>x<nrRegs> vector of <AqlValue>s (not
42
43
// pointers). The size of an <AqlItemBlock> is the number of items.
@@ -71,14 +72,16 @@ class AqlItemBlock {
71
72
72
73
void initFromSlice (arangodb::velocypack::Slice);
73
74
75
+ SerializationFormat getFormatType () const ;
76
+
74
77
protected:
75
78
// / @brief destroy the block
76
79
// / Should only ever be deleted by AqlItemManager::returnBlock, so the
77
80
// / destructor is protected.
78
81
~AqlItemBlock () {
79
82
TRI_ASSERT (_refCount == 0 );
80
83
destroy ();
81
- decreaseMemoryUsage (sizeof (AqlValue) * _nrItems * _nrRegs );
84
+ decreaseMemoryUsage (sizeof (AqlValue) * _nrItems * internalNrRegs () );
82
85
}
83
86
84
87
private:
@@ -97,23 +100,17 @@ class AqlItemBlock {
97
100
public:
98
101
// / @brief getValue, get the value of a register
99
102
inline AqlValue getValue (size_t index, RegisterId varNr) const {
100
- TRI_ASSERT (index < _nrItems);
101
- TRI_ASSERT (varNr < _nrRegs);
102
- return _data[index * _nrRegs + varNr];
103
+ return _data[getAddress (index, varNr)];
103
104
}
104
105
105
106
// / @brief getValue, get the value of a register by reference
106
107
inline AqlValue const & getValueReference (size_t index, RegisterId varNr) const {
107
- TRI_ASSERT (index < _nrItems);
108
- TRI_ASSERT (varNr < _nrRegs);
109
- return _data[index * _nrRegs + varNr];
108
+ return _data[getAddress (index, varNr)];
110
109
}
111
110
112
111
// / @brief setValue, set the current value of a register
113
112
inline void setValue (size_t index, RegisterId varNr, AqlValue const & value) {
114
- TRI_ASSERT (index < _nrItems);
115
- TRI_ASSERT (varNr < _nrRegs);
116
- TRI_ASSERT (_data[index * _nrRegs + varNr].isEmpty ());
113
+ TRI_ASSERT (_data[getAddress (index, varNr)].isEmpty ());
117
114
118
115
// First update the reference count, if this fails, the value is empty
119
116
if (value.requiresDestruction ()) {
@@ -123,27 +120,24 @@ class AqlItemBlock {
123
120
}
124
121
}
125
122
126
- _data[index * _nrRegs + varNr] = value;
123
+ _data[getAddress ( index, varNr) ] = value;
127
124
}
128
125
129
126
// / @brief emplaceValue, set the current value of a register, constructing
130
127
// / it in place
131
128
template <typename ... Args>
132
- // std::enable_if_t<!(std::is_same<AqlValue,std::decay_t<Args>>::value || ...), void>
133
- void
134
- emplaceValue (size_t index, RegisterId varNr, Args&&... args) {
135
- TRI_ASSERT (index < _nrItems);
136
- TRI_ASSERT (varNr < _nrRegs);
137
-
138
- AqlValue* p = &_data[index * _nrRegs + varNr];
129
+ // std::enable_if_t<!(std::is_same<AqlValue,std::decay_t<Args>>::value || ...), void>
130
+ void emplaceValue (size_t index, RegisterId varNr, Args&&... args) {
131
+ auto address = getAddress (index, varNr);
132
+ AqlValue* p = &_data[address];
139
133
TRI_ASSERT (p->isEmpty ());
140
134
// construct the AqlValue in place
141
135
AqlValue* value;
142
136
try {
143
137
value = new (p) AqlValue (std::forward<Args>(args)...);
144
138
} catch (...) {
145
139
// clean up the cell
146
- _data[index * _nrRegs + varNr ].erase ();
140
+ _data[address ].erase ();
147
141
throw ;
148
142
}
149
143
@@ -159,7 +153,7 @@ class AqlItemBlock {
159
153
value->~AqlValue ();
160
154
// TODO - instead of disabling it completly we could you use
161
155
// a constexpr if() with c++17
162
- _data[index * _nrRegs + varNr ].destroy ();
156
+ _data[address ].destroy ();
163
157
throw ;
164
158
}
165
159
}
@@ -169,7 +163,7 @@ class AqlItemBlock {
169
163
// / use with caution only in special situations when it can be ensured that
170
164
// / no one else will be pointing to the same value
171
165
void destroyValue (size_t index, RegisterId varNr) {
172
- auto & element = _data[index * _nrRegs + varNr];
166
+ auto & element = _data[getAddress ( index, varNr) ];
173
167
174
168
if (element.requiresDestruction ()) {
175
169
auto it = _valueCount.find (element);
@@ -190,7 +184,7 @@ class AqlItemBlock {
190
184
// / @brief eraseValue, erase the current value of a register not freeing it
191
185
// / this is used if the value is stolen and later released from elsewhere
192
186
void eraseValue (size_t index, RegisterId varNr) {
193
- auto & element = _data[index * _nrRegs + varNr];
187
+ auto & element = _data[getAddress ( index, varNr) ];
194
188
195
189
if (element.requiresDestruction ()) {
196
190
auto it = _valueCount.find (element);
@@ -214,7 +208,7 @@ class AqlItemBlock {
214
208
// / elsewhere
215
209
void eraseAll () {
216
210
for (size_t i = 0 ; i < numEntries (); i++) {
217
- auto & it = _data[i];
211
+ auto & it = _data[i];
218
212
if (!it.isEmpty ()) {
219
213
it.erase ();
220
214
}
@@ -245,20 +239,23 @@ class AqlItemBlock {
245
239
TRI_ASSERT (currentRow != fromRow);
246
240
247
241
for (RegisterId i = 0 ; i < curRegs; i++) {
248
- if (_data[currentRow * _nrRegs + i].isEmpty ()) {
242
+ auto currentAddress = getAddress (currentRow, i);
243
+ auto fromAddress = getAddress (fromRow, i);
244
+ if (_data[currentAddress].isEmpty ()) {
249
245
// First update the reference count, if this fails, the value is empty
250
- if (_data[fromRow * _nrRegs + i ].requiresDestruction ()) {
251
- ++_valueCount[_data[fromRow * _nrRegs + i ]];
246
+ if (_data[fromAddress ].requiresDestruction ()) {
247
+ ++_valueCount[_data[fromAddress ]];
252
248
}
253
- TRI_ASSERT (_data[currentRow * _nrRegs + i ].isEmpty ());
254
- _data[currentRow * _nrRegs + i ] = _data[fromRow * _nrRegs + i ];
249
+ TRI_ASSERT (_data[currentAddress ].isEmpty ());
250
+ _data[currentAddress ] = _data[fromAddress ];
255
251
}
256
252
}
253
+ // Copy over subqueryDepth
254
+ copySubqueryDepth (currentRow, fromRow);
257
255
}
258
256
259
257
void copyValuesFromRow (size_t currentRow,
260
- std::unordered_set<RegisterId> const & regs,
261
- size_t fromRow) {
258
+ std::unordered_set<RegisterId> const & regs, size_t fromRow) {
262
259
TRI_ASSERT (currentRow != fromRow);
263
260
264
261
for (auto const reg : regs) {
@@ -268,9 +265,11 @@ class AqlItemBlock {
268
265
if (getValueReference (fromRow, reg).requiresDestruction ()) {
269
266
++_valueCount[getValueReference (fromRow, reg)];
270
267
}
271
- _data[currentRow * _nrRegs + reg] = getValueReference (fromRow, reg);
268
+ _data[getAddress ( currentRow, reg) ] = getValueReference (fromRow, reg);
272
269
}
273
270
}
271
+ // Copy over subqueryDepth
272
+ copySubqueryDepth (currentRow, fromRow);
274
273
}
275
274
276
275
// / @brief valueCount
@@ -302,14 +301,11 @@ class AqlItemBlock {
302
301
// / @brief getter for _nrItems
303
302
inline size_t size () const noexcept { return _nrItems; }
304
303
305
-
306
304
// / @brief Number of entries in the matrix. If this changes, the memory usage
307
305
// / must be / in- or decreased appropriately as well.
308
306
// / All entries _data[i] for numEntries() <= i < _data.size() always have to
309
307
// / be erased, i.e. empty / none!
310
- inline size_t numEntries () const {
311
- return _nrRegs * _nrItems;
312
- }
308
+ inline size_t numEntries () const { return internalNrRegs () * _nrItems; }
313
309
314
310
inline size_t capacity () const noexcept { return _data.capacity (); }
315
311
@@ -349,6 +345,35 @@ class AqlItemBlock {
349
345
// / be used to recreate the AqlItemBlock via the Json constructor
350
346
void toVelocyPack (transaction::Methods* trx, arangodb::velocypack::Builder&) const ;
351
347
348
+ // / @brief test if the given row is a shadow row and conveys subquery
349
+ // / information only. It should not be handed to any non-subquery executor.
350
+ bool isShadowRow (size_t row) const {
351
+ // / This value is only filled for shadowRows.
352
+ // / And it is guaranteed to be only filled by numbers this way.
353
+ return _data[getSubqueryDepthAddress (row)].isNumber ();
354
+ }
355
+
356
+ AqlValue const & getShadowRowDepth (size_t row) const {
357
+ TRI_ASSERT (isShadowRow (row));
358
+ return _data[getSubqueryDepthAddress (row)];
359
+ }
360
+
361
+ void setShadowRowDepth (size_t row, AqlValue const & other) {
362
+ TRI_ASSERT (other.isNumber ());
363
+ _data[getSubqueryDepthAddress (row)] = other;
364
+ TRI_ASSERT (isShadowRow (row));
365
+ }
366
+
367
+ void makeShadowRow (size_t row) {
368
+ TRI_ASSERT (!isShadowRow (row));
369
+ _data[getSubqueryDepthAddress (row)] = AqlValue{VPackSlice::zeroSlice ()};
370
+ }
371
+
372
+ void makeDataRow (size_t row) {
373
+ TRI_ASSERT (isShadowRow (row));
374
+ _data[getSubqueryDepthAddress (row)] = AqlValue{VPackSlice::noneSlice ()};
375
+ }
376
+
352
377
protected:
353
378
AqlItemBlockManager& aqlItemBlockManager () noexcept { return _manager; }
354
379
size_t getRefCount () const noexcept { return _refCount; }
@@ -358,6 +383,33 @@ class AqlItemBlock {
358
383
--_refCount;
359
384
}
360
385
386
+ private:
387
+ // This includes the amount of internal registers that are not visible to the outside.
388
+ inline RegisterCount internalNrRegs () const noexcept { return _nrRegs + 1 ; }
389
+
390
+ // / @brief get the computed address within the data vector
391
+ inline size_t getAddress (size_t index, RegisterId varNr) const noexcept {
392
+ TRI_ASSERT (index < _nrItems);
393
+ TRI_ASSERT (varNr < _nrRegs);
394
+ return index * internalNrRegs () + varNr + 1 ;
395
+ }
396
+
397
+ inline size_t getSubqueryDepthAddress (size_t index) const noexcept {
398
+ TRI_ASSERT (index < _nrItems);
399
+ return index * internalNrRegs ();
400
+ }
401
+
402
+ inline void copySubqueryDepth (size_t currentRow, size_t fromRow) {
403
+ auto currentAddress = getSubqueryDepthAddress (currentRow);
404
+ auto fromAddress = getSubqueryDepthAddress (fromRow);
405
+ if (!_data[fromAddress].isEmpty () && _data[currentAddress].isEmpty ()) {
406
+ _data[currentAddress] = _data[fromAddress];
407
+ }
408
+ }
409
+
410
+ void copySubQueryDepthToOtherBlock (SharedAqlItemBlockPtr& target,
411
+ size_t sourceRow, size_t targetRow) const ;
412
+
361
413
private:
362
414
// / @brief _data, the actual data as a single vector of dimensions _nrItems
363
415
// / times _nrRegs
@@ -375,7 +427,7 @@ class AqlItemBlock {
375
427
size_t _nrItems = 0 ;
376
428
377
429
// / @brief _nrRegs, number of columns
378
- RegisterId _nrRegs = 0 ;
430
+ RegisterCount _nrRegs = 0 ;
379
431
380
432
// / @brief manager for this item block
381
433
AqlItemBlockManager& _manager;
0 commit comments