mirror of https://gitee.com/bigwinds/arangodb
reuse more AqlItemBlocks
This commit is contained in:
parent
59b3967273
commit
b76eeee92e
|
@ -206,7 +206,10 @@ void AqlItemBlock::destroy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief shrink the block to the specified number of rows
|
/// @brief shrink the block to the specified number of rows
|
||||||
void AqlItemBlock::shrink(size_t nrItems) {
|
/// if sweep is set, then the superfluous rows are cleaned
|
||||||
|
/// if sweep is not set, the caller has to ensure that the
|
||||||
|
/// superfluous rows are empty
|
||||||
|
void AqlItemBlock::shrink(size_t nrItems, bool sweep) {
|
||||||
TRI_ASSERT(nrItems > 0);
|
TRI_ASSERT(nrItems > 0);
|
||||||
|
|
||||||
if (nrItems == _nrItems) {
|
if (nrItems == _nrItems) {
|
||||||
|
@ -220,28 +223,30 @@ void AqlItemBlock::shrink(size_t nrItems) {
|
||||||
"cannot use shrink() to increase block");
|
"cannot use shrink() to increase block");
|
||||||
}
|
}
|
||||||
|
|
||||||
// erase all stored values in the region that we freed
|
if (sweep) {
|
||||||
for (size_t i = nrItems; i < _nrItems; ++i) {
|
// erase all stored values in the region that we freed
|
||||||
for (RegisterId j = 0; j < _nrRegs; ++j) {
|
for (size_t i = nrItems; i < _nrItems; ++i) {
|
||||||
AqlValue& a(_data[_nrRegs * i + j]);
|
for (RegisterId j = 0; j < _nrRegs; ++j) {
|
||||||
|
AqlValue& a(_data[_nrRegs * i + j]);
|
||||||
|
|
||||||
if (a.requiresDestruction()) {
|
if (a.requiresDestruction()) {
|
||||||
auto it = _valueCount.find(a);
|
auto it = _valueCount.find(a);
|
||||||
|
|
||||||
if (it != _valueCount.end()) {
|
if (it != _valueCount.end()) {
|
||||||
TRI_ASSERT((*it).second > 0);
|
TRI_ASSERT((*it).second > 0);
|
||||||
|
|
||||||
if (--((*it).second) == 0) {
|
if (--((*it).second) == 0) {
|
||||||
decreaseMemoryUsage(a.memoryUsage());
|
decreaseMemoryUsage(a.memoryUsage());
|
||||||
a.destroy();
|
a.destroy();
|
||||||
try {
|
try {
|
||||||
_valueCount.erase(it);
|
_valueCount.erase(it);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
a.erase();
|
||||||
}
|
}
|
||||||
a.erase();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +254,39 @@ void AqlItemBlock::shrink(size_t nrItems) {
|
||||||
|
|
||||||
// adjust the size of the block
|
// adjust the size of the block
|
||||||
_nrItems = nrItems;
|
_nrItems = nrItems;
|
||||||
|
_data.resize(_nrItems * _nrRegs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AqlItemBlock::rescale(size_t nrItems, RegisterId nrRegs) {
|
||||||
|
TRI_ASSERT(_valueCount.empty());
|
||||||
|
TRI_ASSERT(nrRegs > 0);
|
||||||
|
TRI_ASSERT(nrRegs <= ExecutionNode::MaxRegisterId);
|
||||||
|
|
||||||
|
size_t const targetSize = nrItems * nrRegs;
|
||||||
|
size_t const currentSize = _nrItems * _nrRegs;
|
||||||
|
TRI_ASSERT(currentSize <= _data.size());
|
||||||
|
|
||||||
|
if (targetSize > _data.size()) {
|
||||||
|
increaseMemoryUsage(sizeof(AqlValue) * (targetSize - currentSize));
|
||||||
|
try {
|
||||||
|
_data.resize(targetSize);
|
||||||
|
} catch (...) {
|
||||||
|
decreaseMemoryUsage(sizeof(AqlValue) * (targetSize - currentSize));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
} else if (targetSize < _data.size()) {
|
||||||
|
decreaseMemoryUsage(sizeof(AqlValue) * (currentSize - targetSize));
|
||||||
|
try {
|
||||||
|
_data.resize(targetSize);
|
||||||
|
} catch (...) {
|
||||||
|
increaseMemoryUsage(sizeof(AqlValue) * (currentSize - targetSize));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(_data.size() >= targetSize);
|
||||||
|
_nrItems = nrItems;
|
||||||
|
_nrRegs = nrRegs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief clears out some columns (registers), this deletes the values if
|
/// @brief clears out some columns (registers), this deletes the values if
|
||||||
|
|
|
@ -229,9 +229,19 @@ class AqlItemBlock {
|
||||||
|
|
||||||
/// @brief getter for _nrItems
|
/// @brief getter for _nrItems
|
||||||
inline size_t size() const { return _nrItems; }
|
inline size_t size() const { return _nrItems; }
|
||||||
|
|
||||||
|
inline size_t capacity() const { return _data.size(); }
|
||||||
|
|
||||||
/// @brief shrink the block to the specified number of rows
|
/// @brief shrink the block to the specified number of rows
|
||||||
void shrink(size_t nrItems);
|
/// if sweep is set, then the superfluous rows are cleaned
|
||||||
|
/// if sweep is not set, the caller has to ensure that the
|
||||||
|
/// superfluous rows are empty
|
||||||
|
void shrink(size_t nrItems, bool sweep);
|
||||||
|
|
||||||
|
/// @brief rescales the block to the specified dimensions
|
||||||
|
/// note that the block should be empty before rescaling to prevent
|
||||||
|
/// losses of still managed AqlValues
|
||||||
|
void rescale(size_t nrItems, RegisterId nrRegs);
|
||||||
|
|
||||||
/// @brief clears out some columns (registers), this deletes the values if
|
/// @brief clears out some columns (registers), this deletes the values if
|
||||||
/// necessary, using the reference count.
|
/// necessary, using the reference count.
|
||||||
|
|
|
@ -28,37 +28,79 @@ using namespace arangodb::aql;
|
||||||
|
|
||||||
/// @brief create the manager
|
/// @brief create the manager
|
||||||
AqlItemBlockManager::AqlItemBlockManager(ResourceMonitor* resourceMonitor)
|
AqlItemBlockManager::AqlItemBlockManager(ResourceMonitor* resourceMonitor)
|
||||||
: _resourceMonitor(resourceMonitor), _last(nullptr) {}
|
: _resourceMonitor(resourceMonitor) {}
|
||||||
|
|
||||||
/// @brief destroy the manager
|
/// @brief destroy the manager
|
||||||
AqlItemBlockManager::~AqlItemBlockManager() { delete _last; }
|
AqlItemBlockManager::~AqlItemBlockManager() { }
|
||||||
|
|
||||||
/// @brief request a block with the specified size
|
/// @brief request a block with the specified size
|
||||||
AqlItemBlock* AqlItemBlockManager::requestBlock(size_t nrItems,
|
AqlItemBlock* AqlItemBlockManager::requestBlock(size_t nrItems,
|
||||||
RegisterId nrRegs) {
|
RegisterId nrRegs) {
|
||||||
/*
|
// LOG(TRACE) << "requesting AqlItemBlock of " << nrItems << " x " << nrRegs;
|
||||||
if (_last != nullptr && _last->size() == nrItems &&
|
size_t const targetSize = nrItems * nrRegs;
|
||||||
_last->getNrRegs() == nrRegs) {
|
|
||||||
auto block = _last;
|
|
||||||
// don't hand out the same block next time
|
|
||||||
_last = nullptr;
|
|
||||||
block->eraseAll();
|
|
||||||
|
|
||||||
return block;
|
AqlItemBlock* block = nullptr;
|
||||||
|
size_t i = Bucket::getId(targetSize);
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
while (tries++ < 2) {
|
||||||
|
TRI_ASSERT(i < NumBuckets);
|
||||||
|
if (!_buckets[i].empty()) {
|
||||||
|
block = _buckets[i].pop();
|
||||||
|
TRI_ASSERT(block != nullptr);
|
||||||
|
block->eraseAll();
|
||||||
|
block->rescale(nrItems, nrRegs);
|
||||||
|
// LOG(TRACE) << "returned cached AqlItemBlock with dimensions " << block->size() << " x " << block->getNrRegs();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// try next (bigger) bucket
|
||||||
|
if (++i >= NumBuckets) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return new AqlItemBlock(_resourceMonitor, nrItems, nrRegs);
|
if (block == nullptr) {
|
||||||
|
block = new AqlItemBlock(_resourceMonitor, nrItems, nrRegs);
|
||||||
|
// LOG(TRACE) << "created AqlItemBlock with dimensions " << block->size() << " x " << block->getNrRegs();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(block != nullptr);
|
||||||
|
TRI_ASSERT(block->size() == nrItems);
|
||||||
|
TRI_ASSERT(block->getNrRegs() == nrRegs);
|
||||||
|
TRI_ASSERT(block->capacity() >= targetSize);
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief return a block to the manager
|
/// @brief return a block to the manager
|
||||||
void AqlItemBlockManager::returnBlock(AqlItemBlock*& block) {
|
void AqlItemBlockManager::returnBlock(AqlItemBlock*& block) {
|
||||||
TRI_ASSERT(block != nullptr);
|
TRI_ASSERT(block != nullptr);
|
||||||
delete block;
|
|
||||||
/*
|
|
||||||
block->destroy();
|
|
||||||
|
|
||||||
delete _last;
|
// LOG(TRACE) << "returning AqlItemBlock of dimensions " << block->size() << " x " << block->getNrRegs();
|
||||||
_last = block;
|
|
||||||
*/
|
size_t const targetSize = block->size() * block->getNrRegs();
|
||||||
|
size_t const i = Bucket::getId(targetSize);
|
||||||
|
TRI_ASSERT(i < NumBuckets);
|
||||||
|
|
||||||
|
if (!_buckets[i].full()) {
|
||||||
|
// recycle the block
|
||||||
|
block->destroy();
|
||||||
|
// store block in bucket
|
||||||
|
_buckets[i].push(block);
|
||||||
|
} else {
|
||||||
|
// bucket is full. simply delete the block
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
block = nullptr;
|
block = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AqlItemBlockManager::Bucket::Bucket() {
|
||||||
|
for (size_t i = 0; i < NumBlocks; ++i) {
|
||||||
|
blocks[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AqlItemBlockManager::Bucket::~Bucket() {
|
||||||
|
for (size_t i = 0; i < NumBlocks; ++i) {
|
||||||
|
delete blocks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,13 +48,96 @@ class AqlItemBlockManager {
|
||||||
/// @brief return a block to the manager
|
/// @brief return a block to the manager
|
||||||
void returnBlock(AqlItemBlock*& block);
|
void returnBlock(AqlItemBlock*& block);
|
||||||
|
|
||||||
|
ResourceMonitor* resourceMonitor() const { return _resourceMonitor; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResourceMonitor* _resourceMonitor;
|
ResourceMonitor* _resourceMonitor;
|
||||||
|
|
||||||
|
static constexpr size_t NumBuckets = 12;
|
||||||
|
|
||||||
/// @brief last block handed back to the manager
|
struct Bucket {
|
||||||
/// this is the block that may be recycled
|
static constexpr size_t NumBlocks = 4;
|
||||||
AqlItemBlock* _last;
|
|
||||||
|
Bucket();
|
||||||
|
~Bucket();
|
||||||
|
|
||||||
|
std::array<AqlItemBlock*, NumBlocks> blocks;
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return (blocks[0] == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool full() const {
|
||||||
|
return (blocks[NumBlocks - 1] != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
AqlItemBlock* pop() {
|
||||||
|
TRI_ASSERT(!empty());
|
||||||
|
size_t i = NumBlocks;
|
||||||
|
while (i--) {
|
||||||
|
if (blocks[i] != nullptr) {
|
||||||
|
AqlItemBlock* result = blocks[i];
|
||||||
|
blocks[i] = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(AqlItemBlock* block) {
|
||||||
|
TRI_ASSERT(!full());
|
||||||
|
for (size_t i = 0; i < NumBlocks; ++i) {
|
||||||
|
if (blocks[i] == nullptr) {
|
||||||
|
blocks[i] = block;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRI_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t getId(size_t targetSize) {
|
||||||
|
if (targetSize <= 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (targetSize <= 10) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (targetSize <= 20) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (targetSize <= 40) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (targetSize <= 100) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (targetSize <= 200) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if (targetSize <= 400) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (targetSize <= 1000) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if (targetSize <= 2000) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
if (targetSize <= 4000) {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
if (targetSize <= 10000) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Bucket _buckets[NumBuckets];
|
||||||
|
|
||||||
|
static_assert(sizeof(_buckets) <= 400, "buckets memory usage is unexpectedly high");
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,10 @@ int SingletonBlock::getOrSkipSome(size_t, // atLeast,
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterBlock::FilterBlock(ExecutionEngine* engine, FilterNode const* en)
|
FilterBlock::FilterBlock(ExecutionEngine* engine, FilterNode const* en)
|
||||||
: ExecutionBlock(engine, en), _inReg(ExecutionNode::MaxRegisterId) {
|
: ExecutionBlock(engine, en),
|
||||||
|
_inReg(ExecutionNode::MaxRegisterId),
|
||||||
|
_collector(&engine->_itemBlockManager) {
|
||||||
|
|
||||||
auto it = en->getRegisterPlan()->varInfo.find(en->_inVariable->id);
|
auto it = en->getRegisterPlan()->varInfo.find(en->_inVariable->id);
|
||||||
TRI_ASSERT(it != en->getRegisterPlan()->varInfo.end());
|
TRI_ASSERT(it != en->getRegisterPlan()->varInfo.end());
|
||||||
_inReg = it->second.registerId;
|
_inReg = it->second.registerId;
|
||||||
|
@ -284,7 +287,7 @@ int FilterBlock::getOrSkipSome(size_t atLeast, size_t atMost, bool skipping,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipping) {
|
if (!skipping) {
|
||||||
result = _collector.steal(_engine->getQuery()->resourceMonitor());
|
result = _collector.steal();
|
||||||
}
|
}
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,13 @@
|
||||||
|
|
||||||
#include "BlockCollector.h"
|
#include "BlockCollector.h"
|
||||||
#include "Aql/AqlItemBlock.h"
|
#include "Aql/AqlItemBlock.h"
|
||||||
#include "Aql/ResourceUsage.h"
|
#include "Aql/AqlItemBlockManager.h"
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/Exceptions.h"
|
||||||
|
|
||||||
using namespace arangodb::aql;
|
using namespace arangodb::aql;
|
||||||
|
|
||||||
BlockCollector::BlockCollector() : _blocks{_arena}, _totalSize(0) {}
|
BlockCollector::BlockCollector(AqlItemBlockManager* blockManager)
|
||||||
|
: _blockManager(blockManager), _blocks{_arena}, _totalSize(0) {}
|
||||||
|
|
||||||
BlockCollector::~BlockCollector() { clear(); }
|
BlockCollector::~BlockCollector() { clear(); }
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ RegisterId BlockCollector::nrRegs() const {
|
||||||
void BlockCollector::clear() {
|
void BlockCollector::clear() {
|
||||||
for (auto& it : _blocks) {
|
for (auto& it : _blocks) {
|
||||||
it->eraseAll();
|
it->eraseAll();
|
||||||
delete it;
|
_blockManager->returnBlock(it);
|
||||||
}
|
}
|
||||||
_blocks.clear();
|
_blocks.clear();
|
||||||
_totalSize = 0;
|
_totalSize = 0;
|
||||||
|
@ -67,7 +68,7 @@ void BlockCollector::add(AqlItemBlock* block) {
|
||||||
_totalSize += block->size();
|
_totalSize += block->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
AqlItemBlock* BlockCollector::steal(ResourceMonitor* resourceMonitor) {
|
AqlItemBlock* BlockCollector::steal() {
|
||||||
if (_blocks.empty()) {
|
if (_blocks.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -83,9 +84,10 @@ AqlItemBlock* BlockCollector::steal(ResourceMonitor* resourceMonitor) {
|
||||||
// only got a single result. return it as it is
|
// only got a single result. return it as it is
|
||||||
result = _blocks[0];
|
result = _blocks[0];
|
||||||
} else {
|
} else {
|
||||||
result = AqlItemBlock::concatenate(resourceMonitor, this);
|
result = AqlItemBlock::concatenate(_blockManager->resourceMonitor(), this);
|
||||||
for (auto& it : _blocks) {
|
for (auto& it : _blocks) {
|
||||||
delete it;
|
it->eraseAll();
|
||||||
|
_blockManager->returnBlock(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
namespace aql {
|
namespace aql {
|
||||||
class AqlItemBlock;
|
class AqlItemBlock;
|
||||||
struct ResourceMonitor;
|
class AqlItemBlockManager;
|
||||||
|
|
||||||
class BlockCollector {
|
class BlockCollector {
|
||||||
friend class AqlItemBlock;
|
friend class AqlItemBlock;
|
||||||
|
@ -40,7 +40,7 @@ class BlockCollector {
|
||||||
BlockCollector(BlockCollector const&) = delete;
|
BlockCollector(BlockCollector const&) = delete;
|
||||||
BlockCollector& operator=(BlockCollector const&) = delete;
|
BlockCollector& operator=(BlockCollector const&) = delete;
|
||||||
|
|
||||||
BlockCollector();
|
explicit BlockCollector(AqlItemBlockManager*);
|
||||||
~BlockCollector();
|
~BlockCollector();
|
||||||
|
|
||||||
size_t totalSize() const;
|
size_t totalSize() const;
|
||||||
|
@ -51,9 +51,10 @@ class BlockCollector {
|
||||||
void add(std::unique_ptr<AqlItemBlock> block);
|
void add(std::unique_ptr<AqlItemBlock> block);
|
||||||
void add(AqlItemBlock* block);
|
void add(AqlItemBlock* block);
|
||||||
|
|
||||||
AqlItemBlock* steal(ResourceMonitor*);
|
AqlItemBlock* steal();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AqlItemBlockManager* _blockManager;
|
||||||
SmallVector<AqlItemBlock*>::allocator_type::arena_type _arena;
|
SmallVector<AqlItemBlock*>::allocator_type::arena_type _arena;
|
||||||
SmallVector<AqlItemBlock*> _blocks;
|
SmallVector<AqlItemBlock*> _blocks;
|
||||||
size_t _totalSize;
|
size_t _totalSize;
|
||||||
|
|
|
@ -889,7 +889,7 @@ int DistributeBlock::getOrSkipSomeForShard(size_t atLeast, size_t atMost,
|
||||||
|
|
||||||
std::deque<std::pair<size_t, size_t>>& buf = _distBuffer.at(clientId);
|
std::deque<std::pair<size_t, size_t>>& buf = _distBuffer.at(clientId);
|
||||||
|
|
||||||
BlockCollector collector;
|
BlockCollector collector(&_engine->_itemBlockManager);
|
||||||
|
|
||||||
if (buf.empty()) {
|
if (buf.empty()) {
|
||||||
if (!getBlockForClient(atLeast, atMost, clientId)) {
|
if (!getBlockForClient(atLeast, atMost, clientId)) {
|
||||||
|
@ -929,7 +929,7 @@ int DistributeBlock::getOrSkipSomeForShard(size_t atLeast, size_t atMost,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipping) {
|
if (!skipping) {
|
||||||
result = collector.steal(_engine->getQuery()->resourceMonitor());
|
result = collector.steal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// _buffer is left intact, deleted and cleared at shutdown
|
// _buffer is left intact, deleted and cleared at shutdown
|
||||||
|
|
|
@ -409,7 +409,7 @@ int SortedCollectBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||||
TRI_ASSERT(cur != nullptr);
|
TRI_ASSERT(cur != nullptr);
|
||||||
emitGroup(cur, res.get(), skipped);
|
emitGroup(cur, res.get(), skipped);
|
||||||
++skipped;
|
++skipped;
|
||||||
res->shrink(skipped);
|
res->shrink(skipped, false);
|
||||||
} else {
|
} else {
|
||||||
++skipped;
|
++skipped;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ int SortedCollectBlock::getOrSkipSome(size_t atLeast, size_t atMost,
|
||||||
|
|
||||||
if (!skipping) {
|
if (!skipping) {
|
||||||
TRI_ASSERT(skipped > 0);
|
TRI_ASSERT(skipped > 0);
|
||||||
res->shrink(skipped);
|
res->shrink(skipped, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = res.release();
|
result = res.release();
|
||||||
|
|
|
@ -122,6 +122,10 @@ std::vector<std::string> Collection::shardKeys() const {
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Collection::numberOfShards() const {
|
||||||
|
return getCollection()->numberOfShards();
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief whether or not the collection uses the default sharding
|
/// @brief whether or not the collection uses the default sharding
|
||||||
bool Collection::usesDefaultSharding() const {
|
bool Collection::usesDefaultSharding() const {
|
||||||
return getCollection()->usesDefaultShardKeys();
|
return getCollection()->usesDefaultShardKeys();
|
||||||
|
|
|
@ -76,6 +76,8 @@ struct Collection {
|
||||||
|
|
||||||
/// @brief returns the shard keys of a collection
|
/// @brief returns the shard keys of a collection
|
||||||
std::vector<std::string> shardKeys() const;
|
std::vector<std::string> shardKeys() const;
|
||||||
|
|
||||||
|
size_t numberOfShards() const;
|
||||||
|
|
||||||
/// @brief whether or not the collection uses the default sharding
|
/// @brief whether or not the collection uses the default sharding
|
||||||
bool usesDefaultSharding() const;
|
bool usesDefaultSharding() const;
|
||||||
|
|
|
@ -229,7 +229,7 @@ AqlItemBlock* EnumerateCollectionBlock::getSome(size_t, // atLeast,
|
||||||
|
|
||||||
if (send < atMost) {
|
if (send < atMost) {
|
||||||
// The collection did not have enough results
|
// The collection did not have enough results
|
||||||
res->shrink(send);
|
res->shrink(send, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear out registers no longer needed later:
|
// Clear out registers no longer needed later:
|
||||||
|
|
|
@ -392,7 +392,7 @@ int ExecutionBlock::getOrSkipSome(size_t atLeast, size_t atMost, bool skipping,
|
||||||
}
|
}
|
||||||
|
|
||||||
// if _buffer.size() is > 0 then _pos points to a valid place . . .
|
// if _buffer.size() is > 0 then _pos points to a valid place . . .
|
||||||
BlockCollector collector;
|
BlockCollector collector(&_engine->_itemBlockManager);
|
||||||
|
|
||||||
while (skipped < atLeast) {
|
while (skipped < atLeast) {
|
||||||
if (_buffer.empty()) {
|
if (_buffer.empty()) {
|
||||||
|
@ -464,7 +464,7 @@ int ExecutionBlock::getOrSkipSome(size_t atLeast, size_t atMost, bool skipping,
|
||||||
TRI_ASSERT(result == nullptr);
|
TRI_ASSERT(result == nullptr);
|
||||||
|
|
||||||
if (!skipping) {
|
if (!skipping) {
|
||||||
result = collector.steal(_engine->getQuery()->resourceMonitor());
|
result = collector.steal();
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRI_ERROR_NO_ERROR;
|
return TRI_ERROR_NO_ERROR;
|
||||||
|
|
|
@ -50,8 +50,8 @@ IndexBlock::IndexBlock(ExecutionEngine* engine, IndexNode const* en)
|
||||||
_cursor(nullptr),
|
_cursor(nullptr),
|
||||||
_cursors(_indexes.size()),
|
_cursors(_indexes.size()),
|
||||||
_condition(en->_condition->root()),
|
_condition(en->_condition->root()),
|
||||||
_hasV8Expression(false) {
|
_hasV8Expression(false),
|
||||||
|
_collector(&_engine->_itemBlockManager) {
|
||||||
_mmdr.reset(new ManagedDocumentResult);
|
_mmdr.reset(new ManagedDocumentResult);
|
||||||
|
|
||||||
if (_condition != nullptr) {
|
if (_condition != nullptr) {
|
||||||
|
@ -498,7 +498,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
|
||||||
traceGetSomeBegin();
|
traceGetSomeBegin();
|
||||||
if (_done) {
|
if (_done) {
|
||||||
traceGetSomeEnd(nullptr);
|
traceGetSomeEnd(nullptr);
|
||||||
return _collector.steal(_engine->getQuery()->resourceMonitor());
|
return _collector.steal();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AqlItemBlock> res;
|
std::unique_ptr<AqlItemBlock> res;
|
||||||
|
@ -514,7 +514,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
|
||||||
if (!ExecutionBlock::getBlock(toFetch, toFetch) || (!initIndexes())) {
|
if (!ExecutionBlock::getBlock(toFetch, toFetch) || (!initIndexes())) {
|
||||||
_done = true;
|
_done = true;
|
||||||
traceGetSomeEnd(nullptr);
|
traceGetSomeEnd(nullptr);
|
||||||
return _collector.steal(_engine->getQuery()->resourceMonitor());
|
return _collector.steal();
|
||||||
}
|
}
|
||||||
_pos = 0; // this is in the first block
|
_pos = 0; // this is in the first block
|
||||||
|
|
||||||
|
@ -536,7 +536,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
|
||||||
if (!ExecutionBlock::getBlock(DefaultBatchSize(), DefaultBatchSize())) {
|
if (!ExecutionBlock::getBlock(DefaultBatchSize(), DefaultBatchSize())) {
|
||||||
_done = true;
|
_done = true;
|
||||||
traceGetSomeEnd(nullptr);
|
traceGetSomeEnd(nullptr);
|
||||||
return _collector.steal(_engine->getQuery()->resourceMonitor());
|
return _collector.steal();
|
||||||
}
|
}
|
||||||
_pos = 0; // this is in the first block
|
_pos = 0; // this is in the first block
|
||||||
}
|
}
|
||||||
|
@ -544,7 +544,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
|
||||||
if (!initIndexes()) {
|
if (!initIndexes()) {
|
||||||
_done = true;
|
_done = true;
|
||||||
traceGetSomeEnd(nullptr);
|
traceGetSomeEnd(nullptr);
|
||||||
return _collector.steal(_engine->getQuery()->resourceMonitor());
|
return _collector.steal();
|
||||||
}
|
}
|
||||||
readIndex(atMost);
|
readIndex(atMost);
|
||||||
}
|
}
|
||||||
|
@ -588,7 +588,7 @@ AqlItemBlock* IndexBlock::getSome(size_t atLeast, size_t atMost) {
|
||||||
TRI_ASSERT(res.get() == nullptr);
|
TRI_ASSERT(res.get() == nullptr);
|
||||||
|
|
||||||
if (_collector.totalSize() >= atMost) {
|
if (_collector.totalSize() >= atMost) {
|
||||||
res.reset(_collector.steal(_engine->getQuery()->resourceMonitor()));
|
res.reset(_collector.steal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2406,7 +2406,7 @@ void arangodb::aql::scatterInClusterRule(Optimizer* opt, std::unique_ptr<Executi
|
||||||
plan->registerNode(gatherNode);
|
plan->registerNode(gatherNode);
|
||||||
TRI_ASSERT(remoteNode);
|
TRI_ASSERT(remoteNode);
|
||||||
gatherNode->addDependency(remoteNode);
|
gatherNode->addDependency(remoteNode);
|
||||||
if (!elements.empty()) {
|
if (!elements.empty() && gatherNode->collection()->numberOfShards() > 1) {
|
||||||
gatherNode->setElements(elements);
|
gatherNode->setElements(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2810,10 +2810,12 @@ void arangodb::aql::distributeSortToClusterRule(Optimizer* opt,
|
||||||
// then unlink the filter/calculator from the plan
|
// then unlink the filter/calculator from the plan
|
||||||
plan->unlinkNode(inspectNode);
|
plan->unlinkNode(inspectNode);
|
||||||
// and re-insert into plan in front of the remoteNode
|
// and re-insert into plan in front of the remoteNode
|
||||||
if(thisSortNode->_reinsertInCluster){
|
if (thisSortNode->_reinsertInCluster){
|
||||||
plan->insertDependency(rn, inspectNode);
|
plan->insertDependency(rn, inspectNode);
|
||||||
}
|
}
|
||||||
gatherNode->setElements(thisSortNode->getElements());
|
if (gatherNode->collection()->numberOfShards() > 1) {
|
||||||
|
gatherNode->setElements(thisSortNode->getElements());
|
||||||
|
}
|
||||||
modified = true;
|
modified = true;
|
||||||
// ready to rumble!
|
// ready to rumble!
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue