|
28 | 28 | #include "Aql/BlockCollector.h"
|
29 | 29 | #include "Aql/ExecutionBlock.h"
|
30 | 30 | #include "Aql/ExecutionNode.h"
|
| 31 | +#include "Aql/Range.h" |
| 32 | +#include "Aql/RegisterPlan.h" |
31 | 33 | #include "Aql/SharedAqlItemBlockPtr.h"
|
32 | 34 | #include "Basics/VelocyPackHelper.h"
|
33 | 35 |
|
@@ -711,3 +713,206 @@ void AqlItemBlock::copySubQueryDepthToOtherBlock(SharedAqlItemBlockPtr& target,
|
711 | 713 | TRI_ASSERT(false);
|
712 | 714 | }
|
713 | 715 | }
|
| 716 | + |
| 717 | +AqlItemBlock::~AqlItemBlock() { |
| 718 | + TRI_ASSERT(_refCount == 0); |
| 719 | + destroy(); |
| 720 | + decreaseMemoryUsage(sizeof(AqlValue) * _nrItems * internalNrRegs()); |
| 721 | +} |
| 722 | + |
| 723 | +void AqlItemBlock::increaseMemoryUsage(size_t value) { |
| 724 | + resourceMonitor().increaseMemoryUsage(value); |
| 725 | +} |
| 726 | + |
| 727 | +void AqlItemBlock::decreaseMemoryUsage(size_t value) noexcept { |
| 728 | + resourceMonitor().decreaseMemoryUsage(value); |
| 729 | +} |
| 730 | + |
| 731 | +AqlValue AqlItemBlock::getValue(size_t index, RegisterId varNr) const { |
| 732 | + return _data[getAddress(index, varNr)]; |
| 733 | +} |
| 734 | + |
| 735 | +AqlValue const& AqlItemBlock::getValueReference(size_t index, RegisterId varNr) const { |
| 736 | + return _data[getAddress(index, varNr)]; |
| 737 | +} |
| 738 | + |
| 739 | +void AqlItemBlock::setValue(size_t index, RegisterId varNr, AqlValue const& value) { |
| 740 | + TRI_ASSERT(_data[getAddress(index, varNr)].isEmpty()); |
| 741 | + |
| 742 | + // First update the reference count, if this fails, the value is empty |
| 743 | + if (value.requiresDestruction()) { |
| 744 | + if (++_valueCount[value] == 1) { |
| 745 | + size_t mem = value.memoryUsage(); |
| 746 | + increaseMemoryUsage(mem); |
| 747 | + } |
| 748 | + } |
| 749 | + |
| 750 | + _data[getAddress(index, varNr)] = value; |
| 751 | +} |
| 752 | + |
| 753 | +void AqlItemBlock::destroyValue(size_t index, RegisterId varNr) { |
| 754 | + auto& element = _data[getAddress(index, varNr)]; |
| 755 | + |
| 756 | + if (element.requiresDestruction()) { |
| 757 | + auto it = _valueCount.find(element); |
| 758 | + |
| 759 | + if (it != _valueCount.end()) { |
| 760 | + if (--(it->second) == 0) { |
| 761 | + decreaseMemoryUsage(element.memoryUsage()); |
| 762 | + _valueCount.erase(it); |
| 763 | + element.destroy(); |
| 764 | + return; // no need for an extra element.erase() in this case |
| 765 | + } |
| 766 | + } |
| 767 | + } |
| 768 | + |
| 769 | + element.erase(); |
| 770 | +} |
| 771 | + |
| 772 | +void AqlItemBlock::eraseValue(size_t index, RegisterId varNr) { |
| 773 | + auto& element = _data[getAddress(index, varNr)]; |
| 774 | + |
| 775 | + if (element.requiresDestruction()) { |
| 776 | + auto it = _valueCount.find(element); |
| 777 | + |
| 778 | + if (it != _valueCount.end()) { |
| 779 | + if (--(it->second) == 0) { |
| 780 | + decreaseMemoryUsage(element.memoryUsage()); |
| 781 | + try { |
| 782 | + _valueCount.erase(it); |
| 783 | + } catch (...) { |
| 784 | + } |
| 785 | + } |
| 786 | + } |
| 787 | + } |
| 788 | + |
| 789 | + element.erase(); |
| 790 | +} |
| 791 | + |
| 792 | +void AqlItemBlock::eraseAll() { |
| 793 | + for (size_t i = 0; i < numEntries(); i++) { |
| 794 | + auto& it = _data[i]; |
| 795 | + if (!it.isEmpty()) { |
| 796 | + it.erase(); |
| 797 | + } |
| 798 | + } |
| 799 | + |
| 800 | + for (auto const& it : _valueCount) { |
| 801 | + if (it.second > 0) { |
| 802 | + decreaseMemoryUsage(it.first.memoryUsage()); |
| 803 | + } |
| 804 | + } |
| 805 | + _valueCount.clear(); |
| 806 | +} |
| 807 | + |
| 808 | +void AqlItemBlock::copyValuesFromRow(size_t currentRow, RegisterId curRegs, size_t fromRow) { |
| 809 | + TRI_ASSERT(currentRow != fromRow); |
| 810 | + |
| 811 | + for (RegisterId i = 0; i < curRegs; i++) { |
| 812 | + auto currentAddress = getAddress(currentRow, i); |
| 813 | + auto fromAddress = getAddress(fromRow, i); |
| 814 | + if (_data[currentAddress].isEmpty()) { |
| 815 | + // First update the reference count, if this fails, the value is empty |
| 816 | + if (_data[fromAddress].requiresDestruction()) { |
| 817 | + ++_valueCount[_data[fromAddress]]; |
| 818 | + } |
| 819 | + TRI_ASSERT(_data[currentAddress].isEmpty()); |
| 820 | + _data[currentAddress] = _data[fromAddress]; |
| 821 | + } |
| 822 | + } |
| 823 | + // Copy over subqueryDepth |
| 824 | + copySubqueryDepth(currentRow, fromRow); |
| 825 | +} |
| 826 | + |
| 827 | +void AqlItemBlock::copyValuesFromRow(size_t currentRow, |
| 828 | + std::unordered_set<RegisterId> const& regs, |
| 829 | + size_t fromRow) { |
| 830 | + TRI_ASSERT(currentRow != fromRow); |
| 831 | + |
| 832 | + for (auto const reg : regs) { |
| 833 | + TRI_ASSERT(reg < getNrRegs()); |
| 834 | + if (getValueReference(currentRow, reg).isEmpty()) { |
| 835 | + // First update the reference count, if this fails, the value is empty |
| 836 | + if (getValueReference(fromRow, reg).requiresDestruction()) { |
| 837 | + ++_valueCount[getValueReference(fromRow, reg)]; |
| 838 | + } |
| 839 | + _data[getAddress(currentRow, reg)] = getValueReference(fromRow, reg); |
| 840 | + } |
| 841 | + } |
| 842 | + // Copy over subqueryDepth |
| 843 | + copySubqueryDepth(currentRow, fromRow); |
| 844 | +} |
| 845 | + |
| 846 | +void AqlItemBlock::steal(AqlValue const& value) { |
| 847 | + if (value.requiresDestruction()) { |
| 848 | + if (_valueCount.erase(value)) { |
| 849 | + decreaseMemoryUsage(value.memoryUsage()); |
| 850 | + } |
| 851 | + } |
| 852 | +} |
| 853 | + |
| 854 | +RegisterId AqlItemBlock::getNrRegs() const noexcept { return _nrRegs; } |
| 855 | + |
| 856 | +size_t AqlItemBlock::size() const noexcept { return _nrItems; } |
| 857 | + |
| 858 | +size_t AqlItemBlock::numEntries() const { return internalNrRegs() * _nrItems; } |
| 859 | + |
| 860 | +size_t AqlItemBlock::capacity() const noexcept { return _data.capacity(); } |
| 861 | + |
| 862 | +bool AqlItemBlock::isShadowRow(size_t row) const { |
| 863 | + /// This value is only filled for shadowRows. |
| 864 | + /// And it is guaranteed to be only filled by numbers this way. |
| 865 | + return _data[getSubqueryDepthAddress(row)].isNumber(); |
| 866 | +} |
| 867 | + |
| 868 | +AqlValue const& AqlItemBlock::getShadowRowDepth(size_t row) const { |
| 869 | + TRI_ASSERT(isShadowRow(row)); |
| 870 | + return _data[getSubqueryDepthAddress(row)]; |
| 871 | +} |
| 872 | + |
| 873 | +void AqlItemBlock::setShadowRowDepth(size_t row, AqlValue const& other) { |
| 874 | + TRI_ASSERT(other.isNumber()); |
| 875 | + _data[getSubqueryDepthAddress(row)] = other; |
| 876 | + TRI_ASSERT(isShadowRow(row)); |
| 877 | +} |
| 878 | + |
| 879 | +void AqlItemBlock::makeShadowRow(size_t row) { |
| 880 | + TRI_ASSERT(!isShadowRow(row)); |
| 881 | + _data[getSubqueryDepthAddress(row)] = AqlValue{VPackSlice::zeroSlice()}; |
| 882 | +} |
| 883 | + |
| 884 | +void AqlItemBlock::makeDataRow(size_t row) { |
| 885 | + TRI_ASSERT(isShadowRow(row)); |
| 886 | + _data[getSubqueryDepthAddress(row)] = AqlValue{VPackSlice::noneSlice()}; |
| 887 | +} |
| 888 | + |
| 889 | +AqlItemBlockManager& AqlItemBlock::aqlItemBlockManager() noexcept { return _manager; } |
| 890 | + |
| 891 | +size_t AqlItemBlock::getRefCount() const noexcept { return _refCount; } |
| 892 | + |
| 893 | +void AqlItemBlock::incrRefCount() const noexcept { ++_refCount; } |
| 894 | + |
| 895 | +void AqlItemBlock::decrRefCount() const noexcept { |
| 896 | + TRI_ASSERT(_refCount > 0); |
| 897 | + --_refCount; |
| 898 | +} |
| 899 | + |
| 900 | +RegisterCount AqlItemBlock::internalNrRegs() const noexcept { return _nrRegs + 1; } |
| 901 | +size_t AqlItemBlock::getAddress(size_t index, RegisterId varNr) const noexcept { |
| 902 | + TRI_ASSERT(index < _nrItems); |
| 903 | + TRI_ASSERT(varNr < _nrRegs); |
| 904 | + return index * internalNrRegs() + varNr + 1; |
| 905 | +} |
| 906 | + |
| 907 | +size_t AqlItemBlock::getSubqueryDepthAddress(size_t index) const noexcept { |
| 908 | + TRI_ASSERT(index < _nrItems); |
| 909 | + return index * internalNrRegs(); |
| 910 | +} |
| 911 | + |
| 912 | +void AqlItemBlock::copySubqueryDepth(size_t currentRow, size_t fromRow) { |
| 913 | + auto currentAddress = getSubqueryDepthAddress(currentRow); |
| 914 | + auto fromAddress = getSubqueryDepthAddress(fromRow); |
| 915 | + if (!_data[fromAddress].isEmpty() && _data[currentAddress].isEmpty()) { |
| 916 | + _data[currentAddress] = _data[fromAddress]; |
| 917 | + } |
| 918 | +} |
0 commit comments