Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide framework for generic lazily evaluated operation results #1350

Draft
wants to merge 88 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
80667bd
Rename ResultTable -> Result
RobinTF Apr 19, 2024
31b2c11
Wrap idTable in variant
RobinTF Apr 19, 2024
4d0204c
Add ability to create `Result` from generator
RobinTF Apr 19, 2024
515ed0c
Start fixing caching issues
RobinTF Apr 22, 2024
ca1cbed
Avoid another class of exceptions
RobinTF Apr 22, 2024
9e7f3cb
Optimize imports
RobinTF Apr 23, 2024
4c75d42
Introduce ReusableGenerator class
RobinTF Apr 23, 2024
892e4a5
Try to make caching work
RobinTF Apr 23, 2024
586365c
Fiddle around with const a bit
RobinTF Apr 23, 2024
80e2dbd
Add more TODOs
RobinTF Apr 23, 2024
18ca5b1
Fix TextLimit code after rebase
RobinTF Apr 28, 2024
86a9f4b
Fix compilation issues for ReusableGenerator
RobinTF Apr 28, 2024
7f0a5e7
Remove offset calculations from exporter
RobinTF Apr 28, 2024
aee20dd
Fix typo
RobinTF Apr 28, 2024
7576b2e
Add comments
RobinTF Apr 28, 2024
7765a25
Make supportsLimit private to avoid misuse
RobinTF Apr 28, 2024
f815be8
Properly use minimum limit if present
RobinTF May 1, 2024
90cca50
Start adding code to manipulate code after cache extraction
RobinTF May 1, 2024
694c21f
Implement fallback mechanism for failed cache share
RobinTF May 5, 2024
ea8b81f
Fix accidental edit of Usage.md
RobinTF May 5, 2024
50e4529
Consume result as master
RobinTF May 5, 2024
16eedd8
Add proper condition variables
RobinTF May 10, 2024
bf8f085
Implement code that allows for proper recomputation of cache size
RobinTF May 10, 2024
771eb5b
Refactor a bit
RobinTF May 12, 2024
8aa9060
Aggregate tables at the end of lazy results
RobinTF May 12, 2024
b499c6e
Overload constructor of Result class
RobinTF May 17, 2024
6b3f05c
Try to properly calculate duration
RobinTF May 18, 2024
ff5a6ea
Apply formatting
RobinTF May 18, 2024
b974c7d
Fix compilation on gcc 11 and gcc 12
RobinTF May 18, 2024
8b99020
Add correct visibility modifiers
RobinTF May 18, 2024
5f8ab65
Try fixing the compilation issue for real this time
RobinTF May 18, 2024
3a95ef5
Try to fix compilation issue on macOS
RobinTF May 18, 2024
e2dc667
Implement PoC lazy operation for index scan and filter operations
RobinTF May 20, 2024
070494f
Fix double limit offset row
RobinTF May 20, 2024
f631c13
Fix wrong assertion
RobinTF May 20, 2024
c249628
Properly request lazy results when limit clause is present
RobinTF May 20, 2024
ea7fd79
Fix bugs and segfaults
RobinTF May 20, 2024
1e9d0d6
Formatting
RobinTF May 21, 2024
dfb7ba6
Apply small refactoring change
RobinTF May 21, 2024
7d01e59
Correct wrong order of ternary statement
RobinTF May 22, 2024
5b2335a
Add TODO
RobinTF May 22, 2024
93a5892
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF May 23, 2024
9c445ea
Change how maxSend works
RobinTF May 23, 2024
b9ca4aa
Correct call order
RobinTF May 23, 2024
43dddd0
Correct call order
RobinTF May 23, 2024
4ac7892
Rethink approach to apply limits and offset
RobinTF May 27, 2024
ef17e67
Add back headers
RobinTF May 27, 2024
aabb81b
Add back result limiter for subqueries
RobinTF Jun 1, 2024
66a38b4
Try to fix subtle bug with runtime information detail
RobinTF Jun 1, 2024
999baee
Merge branch 'max-send-changes' into refactor-result-table
RobinTF Jun 5, 2024
c291ff7
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jun 5, 2024
9f17e07
Add back comment
RobinTF Jun 5, 2024
389f3f1
Rename `resultTable` -> `result`
RobinTF Jun 5, 2024
000af28
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jun 6, 2024
ba142a0
Add correctness check to prevent double move due to race condition
RobinTF Jun 9, 2024
44562c7
Start implementing tests for new cache feature and fixing bugs along …
RobinTF Jun 13, 2024
0f3a59a
Some Test cleanup
RobinTF Jun 13, 2024
d226849
Mark variable as maybe_unused
RobinTF Jun 13, 2024
552a268
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jun 13, 2024
cde135a
Restructure recomputeSize a bit to avoid unwanted behaviour
RobinTF Jun 13, 2024
cf6b4c9
Add remaining cache tests
RobinTF Jun 14, 2024
b2138bf
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jun 14, 2024
0c589e3
Add tests for `IteratorWrapper`
RobinTF Jun 14, 2024
c465685
Fix line endings
RobinTF Jun 15, 2024
d17fc7d
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jun 28, 2024
93c2360
Add tests for CacheableGenerator
RobinTF Jun 29, 2024
15b435e
Add Filter tests
RobinTF Jun 29, 2024
633bf06
Clear Cache before running tests
RobinTF Jun 29, 2024
6d5a95e
Add test to fix coverage
RobinTF Jun 30, 2024
55b4fec
Address some sonarcloud issues
RobinTF Jun 30, 2024
e5ceacc
Add tests for ExportQueryExecutionTrees
RobinTF Jun 30, 2024
d172dc8
Divide Result class into 3 dedicated classes
RobinTF Jul 5, 2024
5b004b8
Merge remote-tracking branch 'ad-freiburg/master' into refactor-resul…
RobinTF Jul 5, 2024
b95edfd
Remove parameter for supportsLimit
RobinTF Jul 5, 2024
acc99c3
Fix formatting
RobinTF Jul 5, 2024
7900619
Format again
RobinTF Jul 5, 2024
0d0133a
Also perform definedness check for lazy results
RobinTF Jul 5, 2024
27ab692
Drop definedness caching mechanism
RobinTF Jul 5, 2024
2da169f
Add comment
RobinTF Jul 5, 2024
0cbb47d
Split lambdas into dedicated functions
RobinTF Jul 6, 2024
5adda07
Make move/copy constructors explicit
RobinTF Jul 6, 2024
e0cdf18
Fix undefined behaviour
RobinTF Jul 6, 2024
5ad5b8a
Workaround segfault
RobinTF Jul 6, 2024
db187f0
Try different attempt to fix double locking
RobinTF Jul 7, 2024
4ba81bd
Avoid pseudo false-positive thread sanitizer warning
RobinTF Jul 7, 2024
373f009
Restructure code to avoid class of race conditions
RobinTF Jul 11, 2024
27e451e
Clarify currently buggy behaviour
RobinTF Jul 11, 2024
96982aa
Fix macOS build
RobinTF Jul 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/engine/Bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ std::vector<QueryExecutionTree*> Bind::getChildren() {
}

// _____________________________________________________________________________
Result Bind::computeResult([[maybe_unused]] bool requestLaziness) {
ProtoResult Bind::computeResult([[maybe_unused]] bool requestLaziness) {
using std::endl;
LOG(DEBUG) << "Get input to BIND operation..." << endl;
std::shared_ptr<const Result> subRes = _subtree->getResult();
Expand Down
2 changes: 1 addition & 1 deletion src/engine/Bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Bind : public Operation {
[[nodiscard]] vector<ColumnIndex> resultSortedOn() const override;

private:
Result computeResult([[maybe_unused]] bool requestLaziness) override;
ProtoResult computeResult([[maybe_unused]] bool requestLaziness) override;

// Implementation for the binding of arbitrary expressions.
template <size_t IN_WIDTH, size_t OUT_WIDTH>
Expand Down
2 changes: 1 addition & 1 deletion src/engine/CartesianProductJoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void CartesianProductJoin::writeResultColumn(std::span<Id> targetColumn,
}
}
// ____________________________________________________________________________
Result CartesianProductJoin::computeResult(
ProtoResult CartesianProductJoin::computeResult(
[[maybe_unused]] bool requestLaziness) {
IdTable result{getExecutionContext()->getAllocator()};
result.setNumColumns(getResultWidth());
Expand Down
2 changes: 1 addition & 1 deletion src/engine/CartesianProductJoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class CartesianProductJoin : public Operation {

private:
//! Compute the result of the query-subtree rooted at this element..
Result computeResult([[maybe_unused]] bool requestLaziness) override;
ProtoResult computeResult([[maybe_unused]] bool requestLaziness) override;

// Copy each element from the `inputColumn` `groupSize` times to the
// `targetColumn`. Repeat until the `targetColumn` is completely filled. Skip
Expand Down
2 changes: 1 addition & 1 deletion src/engine/CountAvailablePredicates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ size_t CountAvailablePredicates::getCostEstimate() {
}

// _____________________________________________________________________________
Result CountAvailablePredicates::computeResult(
ProtoResult CountAvailablePredicates::computeResult(
[[maybe_unused]] bool requestLaziness) {
LOG(DEBUG) << "CountAvailablePredicates result computation..." << std::endl;
IdTable idTable{getExecutionContext()->getAllocator()};
Expand Down
2 changes: 1 addition & 1 deletion src/engine/CountAvailablePredicates.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@ class CountAvailablePredicates : public Operation {
void computePatternTrickAllEntities(
IdTable* result, const CompactVectorOfStrings<Id>& patterns) const;

Result computeResult([[maybe_unused]] bool requestLaziness) override;
ProtoResult computeResult([[maybe_unused]] bool requestLaziness) override;
[[nodiscard]] VariableToColumnMap computeVariableToColumnMap() const override;
};
2 changes: 1 addition & 1 deletion src/engine/Distinct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ VariableToColumnMap Distinct::computeVariableToColumnMap() const {
}

// _____________________________________________________________________________
Result Distinct::computeResult([[maybe_unused]] bool requestLaziness) {
ProtoResult Distinct::computeResult([[maybe_unused]] bool requestLaziness) {
IdTable idTable{getExecutionContext()->getAllocator()};
LOG(DEBUG) << "Getting sub-result for distinct result computation..." << endl;
std::shared_ptr<const Result> subRes = _subtree->getResult();
Expand Down
3 changes: 2 additions & 1 deletion src/engine/Distinct.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class Distinct : public Operation {
[[nodiscard]] string getCacheKeyImpl() const override;

private:
virtual Result computeResult([[maybe_unused]] bool requestLaziness) override;
virtual ProtoResult computeResult(
[[maybe_unused]] bool requestLaziness) override;

VariableToColumnMap computeVariableToColumnMap() const override;
};
83 changes: 52 additions & 31 deletions src/engine/ExportQueryExecutionTrees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,48 @@
#include "util/http/MediaTypes.h"

// __________________________________________________________________________
namespace {

cppcoro::generator<const IdTable&> ExportQueryExecutionTrees::getIdTables(
const Result& result) {
if (result.isDataEvaluated()) {
co_yield result.idTable();
} else {
for (const IdTable& idTable : result.idTables()) {
co_yield idTable;
}
}
}

// Return a range that contains the indices of the rows that have to be exported
// from the `idTable` given the `LimitOffsetClause`. It takes into account the
// LIMIT, the OFFSET, and the actual size of the `idTable`
auto getRowIndices(const LimitOffsetClause& limitOffset, const Result& result) {
const IdTable& idTable = result.idTable();
return std::views::iota(limitOffset.actualOffset(idTable.size()),
limitOffset.upperBound(idTable.size()));
cppcoro::generator<ExportQueryExecutionTrees::IndexWithTable>
ExportQueryExecutionTrees::getRowIndices(LimitOffsetClause limitOffset,
const Result& result) {
for (const IdTable& idTable : getIdTables(result)) {
uint64_t currentOffset = limitOffset.actualOffset(idTable.numRows());
uint64_t upperBound = limitOffset.upperBound(idTable.numRows());
for (size_t index = currentOffset; index < upperBound; index++) {
co_yield {index, idTable};
}
limitOffset._offset -= currentOffset;
if (limitOffset._limit.has_value()) {
limitOffset._limit =
limitOffset._limit.value() - (upperBound - currentOffset);
}
}
}
} // namespace

// _____________________________________________________________________________
cppcoro::generator<QueryExecutionTree::StringTriple>
ExportQueryExecutionTrees::constructQueryResultToTriples(
const QueryExecutionTree& qet,
const ad_utility::sparql_types::Triples& constructTriples,
LimitOffsetClause limitAndOffset, std::shared_ptr<const Result> res,
LimitOffsetClause limitAndOffset, std::shared_ptr<const Result> result,
CancellationHandle cancellationHandle) {
for (size_t i : getRowIndices(limitAndOffset, *res)) {
ConstructQueryExportContext context{i, *res, qet.getVariableColumns(),
for (auto [i, idTable] : getRowIndices(limitAndOffset, *result)) {
ConstructQueryExportContext context{i, idTable, result->localVocab(),
qet.getVariableColumns(),
qet.getQec()->getIndex()};
using enum PositionInTriple;
for (const auto& triple : constructTriples) {
Expand Down Expand Up @@ -111,10 +133,9 @@ nlohmann::json ExportQueryExecutionTrees::idTableToQLeverJSONArray(
std::shared_ptr<const Result> result,
CancellationHandle cancellationHandle) {
AD_CORRECTNESS_CHECK(result != nullptr);
const IdTable& data = result->idTable();
nlohmann::json json = nlohmann::json::array();

for (size_t rowIndex : getRowIndices(limitAndOffset, *result)) {
for (auto [rowIndex, idTable] : getRowIndices(limitAndOffset, *result)) {
// We need the explicit `array` constructor for the special case of zero
// variables.
json.push_back(nlohmann::json::array());
Expand All @@ -124,7 +145,7 @@ nlohmann::json ExportQueryExecutionTrees::idTableToQLeverJSONArray(
row.emplace_back(nullptr);
continue;
}
const auto& currentId = data(rowIndex, opt->columnIndex_);
const auto& currentId = idTable(rowIndex, opt->columnIndex_);
const auto& optionalStringAndXsdType = idToStringAndType(
qet.getQec()->getIndex(), currentId, result->localVocab());
if (!optionalStringAndXsdType.has_value()) {
Expand Down Expand Up @@ -231,7 +252,7 @@ ExportQueryExecutionTrees::idToStringAndType(const Index& index, Id id,
return std::pair{escapeFunction(word.toStringRepresentation()), nullptr};
};
switch (id.getDatatype()) {
case Datatype::WordVocabIndex: {
case WordVocabIndex: {
std::optional<string> entity =
index.idToOptionalString(id.getWordVocabIndex());
AD_CONTRACT_CHECK(entity.has_value());
Expand Down Expand Up @@ -290,8 +311,6 @@ nlohmann::json ExportQueryExecutionTrees::selectQueryResultToSparqlJSON(

std::erase(columns, std::nullopt);

const IdTable& idTable = result->idTable();

json resultJson;
std::vector<std::string> selectedVars =
selectClause.getSelectedVariablesAsStrings();
Expand Down Expand Up @@ -359,7 +378,7 @@ nlohmann::json ExportQueryExecutionTrees::selectQueryResultToSparqlJSON(
return b;
};

for (size_t rowIndex : getRowIndices(limitAndOffset, *result)) {
for (auto [rowIndex, idTable] : getRowIndices(limitAndOffset, *result)) {
// TODO: ordered_json` entries are ordered alphabetically, but insertion
// order would be preferable.
nlohmann::ordered_json binding;
Expand Down Expand Up @@ -432,10 +451,9 @@ ExportQueryExecutionTrees::selectQueryResultToStream(
auto selectedColumnIndices =
qet.selectedVariablesToColumnIndices(selectClause, true);

const auto& idTable = result->idTable();
// special case : binary export of IdTable
if constexpr (format == MediaType::octetStream) {
for (size_t i : getRowIndices(limitAndOffset, *result)) {
for (auto [i, idTable] : getRowIndices(limitAndOffset, *result)) {
for (const auto& columnIndex : selectedColumnIndices) {
if (columnIndex.has_value()) {
co_yield std::string_view{reinterpret_cast<const char*>(&idTable(
Expand Down Expand Up @@ -463,7 +481,7 @@ ExportQueryExecutionTrees::selectQueryResultToStream(
constexpr auto& escapeFunction = format == MediaType::tsv
? RdfEscaping::escapeForTsv
: RdfEscaping::escapeForCsv;
for (size_t i : getRowIndices(limitAndOffset, *result)) {
for (auto [i, idTable] : getRowIndices(limitAndOffset, *result)) {
for (size_t j = 0; j < selectedColumnIndices.size(); ++j) {
if (selectedColumnIndices[j].has_value()) {
const auto& val = selectedColumnIndices[j].value();
Expand Down Expand Up @@ -583,11 +601,10 @@ ad_utility::streams::stream_generator ExportQueryExecutionTrees::
co_yield "\n<results>";

result->logResultSize();
const auto& idTable = result->idTable();
auto selectedColumnIndices =
qet.selectedVariablesToColumnIndices(selectClause, false);
// TODO<joka921> we could prefilter for the nonexisting variables.
for (size_t i : getRowIndices(limitAndOffset, *result)) {
for (auto [i, idTable] : getRowIndices(limitAndOffset, *result)) {
co_yield "\n <result>";
for (size_t j = 0; j < selectedColumnIndices.size(); ++j) {
if (selectedColumnIndices[j].has_value()) {
Expand Down Expand Up @@ -644,11 +661,16 @@ nlohmann::json ExportQueryExecutionTrees::computeQueryResultAsQLeverJSON(
const ParsedQuery& query, const QueryExecutionTree& qet,
const ad_utility::Timer& requestTimer,
CancellationHandle cancellationHandle) {
std::shared_ptr<const Result> result = qet.getResult();
std::shared_ptr<const Result> result =
qet.getResult(query._limitOffset._limit.has_value());
result->logResultSize();
// TODO<RobinTF> this timer only makes sense for non lazy results.
auto timeResultComputation = requestTimer.msecs();

size_t resultSize = result->idTable().size();
std::optional<size_t> resultSize =
query.hasSelectClause() && result->isDataEvaluated()
? std::optional{result->idTable().size()}
: std::nullopt;

nlohmann::json j;

Expand Down Expand Up @@ -680,7 +702,7 @@ nlohmann::json ExportQueryExecutionTrees::computeQueryResultAsQLeverJSON(
qet, query.constructClause().triples_, query._limitOffset,
std::move(result), std::move(cancellationHandle));
}
j["resultsize"] = query.hasSelectClause() ? resultSize : j["res"].size();
j["resultsize"] = resultSize.value_or(j["res"].size());
j["time"]["total"] = std::to_string(requestTimer.msecs().count()) + "ms";
j["time"]["computeResult"] =
std::to_string(timeResultComputation.count()) + "ms";
Expand All @@ -694,15 +716,14 @@ ExportQueryExecutionTrees::computeResultAsStream(
const ParsedQuery& parsedQuery, const QueryExecutionTree& qet,
ad_utility::MediaType mediaType, CancellationHandle cancellationHandle) {
auto compute = [&]<MediaType format> {
auto limitAndOffset = parsedQuery._limitOffset;
return parsedQuery.hasSelectClause()
? ExportQueryExecutionTrees::selectQueryResultToStream<format>(
qet, parsedQuery.selectClause(), limitAndOffset,
? selectQueryResultToStream<format>(
qet, parsedQuery.selectClause(), parsedQuery._limitOffset,
std::move(cancellationHandle))
: ExportQueryExecutionTrees::constructQueryResultToStream<
format>(qet, parsedQuery.constructClause().triples_,
limitAndOffset, qet.getResult(),
std::move(cancellationHandle));
: constructQueryResultToStream<format>(
qet, parsedQuery.constructClause().triples_,
parsedQuery._limitOffset, qet.getResult(),
std::move(cancellationHandle));
};

using enum MediaType;
Expand Down
24 changes: 24 additions & 0 deletions src/engine/ExportQueryExecutionTrees.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,28 @@ class ExportQueryExecutionTrees {
const QueryExecutionTree& qet,
const parsedQuery::SelectClause& selectClause,
LimitOffsetClause limitAndOffset, CancellationHandle cancellationHandle);

struct IndexWithTable {
size_t index_;
const IdTable& idTable_;
};

static cppcoro::generator<const IdTable&> getIdTables(const Result& result);
// Return a range that contains the indices of the rows that have to be
// exported from the `idTable` given the `LimitOffsetClause`. It takes into
// account the LIMIT, the OFFSET, and the actual size of the `idTable`
static cppcoro::generator<IndexWithTable> getRowIndices(
LimitOffsetClause limitOffset, const Result& result);

FRIEND_TEST(ExportQueryExecutionTrees, getIdTablesReturnsSingletonIterator);
FRIEND_TEST(ExportQueryExecutionTrees, getIdTablesMirrorsGenerator);
FRIEND_TEST(ExportQueryExecutionTrees, ensureCorrectSlicingOfSingleIdTable);
FRIEND_TEST(ExportQueryExecutionTrees,
ensureCorrectSlicingOfIdTablesWhenFirstIsSkipped);
FRIEND_TEST(ExportQueryExecutionTrees,
ensureCorrectSlicingOfIdTablesWhenLastIsSkipped);
FRIEND_TEST(ExportQueryExecutionTrees,
ensureCorrectSlicingOfIdTablesWhenFirstAndSecondArePartial);
FRIEND_TEST(ExportQueryExecutionTrees,
ensureCorrectSlicingOfIdTablesWhenFirstAndLastArePartial);
};
72 changes: 49 additions & 23 deletions src/engine/Filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,41 +43,67 @@ string Filter::getDescriptor() const {
}

// _____________________________________________________________________________
Result Filter::computeResult([[maybe_unused]] bool requestLaziness) {
ProtoResult Filter::computeResult(bool requestLaziness) {
LOG(DEBUG) << "Getting sub-result for Filter result computation..." << endl;
std::shared_ptr<const Result> subRes = _subtree->getResult();
std::shared_ptr<const Result> subRes = _subtree->getResult(requestLaziness);
LOG(DEBUG) << "Filter result computation..." << endl;
checkCancellation();

IdTable idTable{getExecutionContext()->getAllocator()};
idTable.setNumColumns(subRes->idTable().numColumns());

size_t width = idTable.numColumns();
CALL_FIXED_SIZE(width, &Filter::computeFilterImpl, this, &idTable, *subRes);
LOG(DEBUG) << "Filter result computation done." << endl;
checkCancellation();
if (subRes->isDataEvaluated()) {
sparqlExpression::EvaluationContext evaluationContext(
*getExecutionContext(), _subtree->getVariableColumns(),
subRes->idTable(), getExecutionContext()->getAllocator(),
subRes->localVocab(), cancellationHandle_);

// TODO<joka921> This should be a mandatory argument to the
// EvaluationContext constructor.
evaluationContext._columnsByWhichResultIsSorted = subRes->sortedBy();

size_t width = evaluationContext._inputTable.numColumns();
IdTable result = CALL_FIXED_SIZE(width, &Filter::computeFilterImpl, this,
evaluationContext);
LOG(DEBUG) << "Filter result computation done." << endl;
checkCancellation();

return {std::move(result), resultSortedOn(), subRes->getSharedLocalVocab()};
}
return {filterInChunks(subRes), resultSortedOn(),
subRes->getSharedLocalVocab()};
}

return {std::move(idTable), resultSortedOn(), subRes->getSharedLocalVocab()};
// _____________________________________________________________________________
cppcoro::generator<IdTable> Filter::filterInChunks(
std::shared_ptr<const Result> subRes) {
for (const IdTable& idTable : subRes->idTables()) {
sparqlExpression::EvaluationContext evaluationContext(
*getExecutionContext(), _subtree->getVariableColumns(), idTable,
getExecutionContext()->getAllocator(), subRes->localVocab(),
cancellationHandle_);

// TODO<joka921> This should be a mandatory argument to the
// EvaluationContext constructor.
evaluationContext._columnsByWhichResultIsSorted = subRes->sortedBy();

size_t width = evaluationContext._inputTable.numColumns();
co_yield CALL_FIXED_SIZE(width, &Filter::computeFilterImpl, this,
evaluationContext);
LOG(DEBUG) << "Filter result chunk done." << endl;
checkCancellation();
}
}

// _____________________________________________________________________________
template <size_t WIDTH>
void Filter::computeFilterImpl(IdTable* outputIdTable,
const Result& inputResultTable) {
sparqlExpression::EvaluationContext evaluationContext(
*getExecutionContext(), _subtree->getVariableColumns(),
inputResultTable.idTable(), getExecutionContext()->getAllocator(),
inputResultTable.localVocab(), cancellationHandle_);

// TODO<joka921> This should be a mandatory argument to the EvaluationContext
// constructor.
evaluationContext._columnsByWhichResultIsSorted = inputResultTable.sortedBy();
IdTable Filter::computeFilterImpl(
sparqlExpression::EvaluationContext& evaluationContext) {
IdTable idTable{getExecutionContext()->getAllocator()};
idTable.setNumColumns(evaluationContext._inputTable.numColumns());

sparqlExpression::ExpressionResult expressionResult =
_expression.getPimpl()->evaluate(&evaluationContext);

const auto input = inputResultTable.idTable().asStaticView<WIDTH>();
auto output = std::move(*outputIdTable).toStatic<WIDTH>();
const auto input = evaluationContext._inputTable.asStaticView<WIDTH>();
auto output = std::move(idTable).toStatic<WIDTH>();
// Clang 17 seems to incorrectly deduce the type, so try to trick it
std::remove_const_t<decltype(output)>& output2 = output;

Expand Down Expand Up @@ -123,7 +149,7 @@ void Filter::computeFilterImpl(IdTable* outputIdTable,

std::visit(visitor, std::move(expressionResult));

*outputIdTable = std::move(output).toDynamic();
return std::move(output).toDynamic();
}

// _____________________________________________________________________________
Expand Down
Loading
Loading