Skip to content

Commit 4e5c6e2

Browse files
committed
Merge upstream/master into improveConstructQueryResultToTriples
2 parents a36aedd + cca3768 commit 4e5c6e2

36 files changed

+1212
-395
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: "Native build to WebAssembly using Conan and Emscripten"
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
build:
11+
strategy:
12+
fail-fast: false
13+
runs-on: ubuntu-24.04
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
submodules: 'recursive'
19+
- name: Install conan package manager
20+
run: |
21+
sudo apt-get install pipx
22+
pipx ensurepath
23+
source ~/.bashrc
24+
pipx install conan
25+
shell: bash
26+
27+
- name: Set up nodejs v25.
28+
uses: actions/setup-node@v6
29+
with:
30+
node-version: 25
31+
32+
- name: Get build and host profiles for conan
33+
working-directory: ${{github.workspace}}
34+
run: |
35+
conan profile detect
36+
37+
- name: Cache for conan
38+
uses: actions/cache@v3
39+
env:
40+
cache-name: cache-conan-with-emscripten-modules-ubuntu-24.04
41+
with:
42+
path: ~/.conan2
43+
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('conanfile.txt', 'conanprofiles/emscripten.profile')}}
44+
45+
- name: Install and run conan. Also create a build directory.
46+
working-directory: ${{github.workspace}}
47+
run: conan install . -pr:b default -pr:h conanprofiles/emscripten.profile -s build_type=Release -b missing -of build
48+
49+
- name: Configure CMake
50+
working-directory: ${{github.workspace}}/build
51+
run: cmake -S .. -B . -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DLOGLEVEL=INFO -DUSE_PARALLEL=true -D_NO_TIMING_TESTS=ON -D_EMSCRIPTEN_NO_INDEXBUILDER_AND_SERVER=ON -D_NO_BENCHMARK=ON -D_DISABLE_EMSCRIPTEN_PROBLEMATIC_TESTS=ON -GNinja
52+
53+
- name: Build
54+
working-directory: ${{github.workspace}}/build
55+
56+
run: cmake --build .
57+

CMakeLists.txt

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,17 @@ add_subdirectory(test)
478478
add_library(compilationInfo ${CMAKE_CURRENT_BINARY_DIR}/CompilationInfo.cpp)
479479
qlever_target_link_libraries(compilationInfo)
480480

481-
add_executable(qlever-index src/index/IndexBuilderMain.cpp)
482-
qlever_target_link_libraries(qlever-index qlever index ${CMAKE_THREAD_LIBS_INIT} Boost::program_options compilationInfo global)
481+
OPTION(_EMSCRIPTEN_NO_INDEXBUILDER_AND_SERVER "Don't build some targets when compiling with Emscripten." OFF)
483482

484-
add_executable(qlever-server src/ServerMain.cpp)
485-
qlever_target_link_libraries(qlever-server engine server ${CMAKE_THREAD_LIBS_INIT} Boost::program_options compilationInfo global)
486-
if (USE_PRECOMPILED_HEADERS)
487-
target_precompile_headers(qlever-server REUSE_FROM engine)
483+
if (NOT _EMSCRIPTEN_NO_INDEXBUILDER_AND_SERVER)
484+
add_executable(qlever-index src/index/IndexBuilderMain.cpp)
485+
qlever_target_link_libraries(qlever-index qlever index ${CMAKE_THREAD_LIBS_INIT} Boost::program_options compilationInfo global)
486+
487+
add_executable(qlever-server src/ServerMain.cpp)
488+
qlever_target_link_libraries(qlever-server engine server ${CMAKE_THREAD_LIBS_INIT} Boost::program_options compilationInfo global)
489+
if (USE_PRECOMPILED_HEADERS)
490+
target_precompile_headers(qlever-server REUSE_FROM engine)
491+
endif()
488492
endif()
489493

490494
add_executable(LibQLeverExample src/libqlever/LibQLeverExample.cpp)
@@ -496,11 +500,13 @@ qlever_target_link_libraries(VocabularyMergerMain index parser ${CMAKE_THREAD_LI
496500
add_executable(PrintIndexVersionMain src/PrintIndexVersionMain.cpp)
497501
qlever_target_link_libraries(PrintIndexVersionMain util)
498502

499-
install(TARGETS
500-
qlever-index
501-
qlever-server
502-
RUNTIME DESTINATION bin
503-
)
503+
if (NOT _EMSCRIPTEN_NO_INDEXBUILDER_AND_SERVER)
504+
install(TARGETS
505+
qlever-index
506+
qlever-server
507+
RUNTIME DESTINATION bin
508+
)
509+
endif()
504510

505511
###############################################################
506512
# CPack packaging

benchmark/CMakeLists.txt

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,39 @@
11
# Re-compiling all the infrastructure all the time is a waste of time, so we
22
# pre-compile that part as a library.
33

4-
# This part compiles 'just' the benchmark infrastructure and doesn't provide a main function.
5-
add_library(benchmark infrastructure/Benchmark.cpp infrastructure/BenchmarkMeasurementContainer.cpp
6-
infrastructure/BenchmarkToJson.cpp infrastructure/BenchmarkToString.cpp)
7-
qlever_target_link_libraries(benchmark Boost::program_options absl::str_format parser util configManager)
4+
OPTION(_NO_BENCHMARK "Disable benchmark targets, for example when building with Emscripten." OFF)
85

9-
# This provides the library of the benchmark infrastructure together with its default main function.
10-
add_library(benchmarkWithMain infrastructure/BenchmarkMain.cpp)
11-
qlever_target_link_libraries(benchmarkWithMain benchmark)
6+
if (NOT _NO_BENCHMARK)
7+
# This part compiles 'just' the benchmark infrastructure and doesn't provide a main function.
8+
add_library(benchmark infrastructure/Benchmark.cpp infrastructure/BenchmarkMeasurementContainer.cpp
9+
infrastructure/BenchmarkToJson.cpp infrastructure/BenchmarkToString.cpp)
10+
qlever_target_link_libraries(benchmark Boost::program_options absl::str_format parser util configManager)
1211

13-
# Link binary ${basename} against the benchmark library,
14-
# and all libraries that are specified as additional arguments.
15-
function (linkBenchmark basename)
16-
qlever_target_link_libraries(${basename} benchmarkWithMain ${ARGN})
17-
endfunction()
12+
# This provides the library of the benchmark infrastructure together with its default main function.
13+
add_library(benchmarkWithMain infrastructure/BenchmarkMain.cpp)
14+
qlever_target_link_libraries(benchmarkWithMain benchmark)
1815

19-
# Compile the benchmark and link it.
20-
# Usage: addAndLinkBenchmark(baseName, [additionalLibraries...])
21-
# - baseName: The name of the benchmark file without the .cpp ending.
22-
function(addAndLinkBenchmark baseName)
23-
add_executable(${baseName} "${baseName}.cpp")
24-
linkBenchmark(${baseName} ${ARGN})
25-
endfunction()
16+
# Link binary ${basename} against the benchmark library,
17+
# and all libraries that are specified as additional arguments.
18+
function (linkBenchmark basename)
19+
qlever_target_link_libraries(${basename} benchmarkWithMain ${ARGN})
20+
endfunction()
2621

27-
# Add benchmarks after here.
28-
addAndLinkBenchmark(BenchmarkExamples)
22+
# Compile the benchmark and link it.
23+
# Usage: addAndLinkBenchmark(baseName, [additionalLibraries...])
24+
# - baseName: The name of the benchmark file without the .cpp ending.
25+
function(addAndLinkBenchmark baseName)
26+
add_executable(${baseName} "${baseName}.cpp")
27+
linkBenchmark(${baseName} ${ARGN})
28+
endfunction()
2929

30-
addAndLinkBenchmark(JoinAlgorithmBenchmark testUtil memorySize)
30+
# Add benchmarks after here.
31+
addAndLinkBenchmark(BenchmarkExamples)
3132

32-
addAndLinkBenchmark(ParallelMergeBenchmark testUtil)
33+
addAndLinkBenchmark(JoinAlgorithmBenchmark testUtil memorySize)
3334

34-
addAndLinkBenchmark(GroupByHashMapBenchmark engine testUtil gtest gmock)
35+
addAndLinkBenchmark(ParallelMergeBenchmark testUtil)
36+
37+
addAndLinkBenchmark(GroupByHashMapBenchmark engine testUtil gtest gmock)
38+
39+
endif()

conanprofiles/emscripten.profile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[settings]
2+
arch=wasm64
3+
build_type=Release
4+
compiler=emcc
5+
compiler.cppstd=20
6+
compiler.libcxx=libc++
7+
# emsdk 3.1.73 is the latest version provided by the Conan package manager.
8+
compiler.version=3.1.73
9+
os=Emscripten
10+
compiler.threads=posix
11+
12+
[tool_requires]
13+
emsdk/3.1.73
14+
15+
[options]
16+
icu/*:with_icuio=False
17+
18+
boost/*:without_atomic=True
19+
boost/*:without_charconv=True
20+
boost/*:without_chrono=True
21+
boost/*:without_context=True
22+
boost/*:without_contract=True
23+
boost/*:without_coroutine=True
24+
boost/*:without_date_time=True
25+
boost/*:without_exception=True
26+
boost/*:without_fiber=True
27+
boost/*:without_filesystem=True
28+
boost/*:without_graph=True
29+
boost/*:without_json=True
30+
boost/*:without_locale=True
31+
boost/*:without_log=True
32+
boost/*:without_math=True
33+
boost/*:without_nowide=True
34+
boost/*:without_process=True
35+
boost/*:without_serialization=True
36+
boost/*:without_stacktrace=True
37+
boost/*:without_test=True
38+
boost/*:without_thread=True
39+
boost/*:without_timer=True
40+
boost/*:without_type_erasure=True
41+
boost/*:without_wave=True
42+
43+
[conf]
44+
tools.cmake.cmaketoolchain:generator=Ninja
45+
tools.build:exelinkflags=['-sALLOW_MEMORY_GROWTH=1', '-sMAXIMUM_MEMORY=4GB', '-sINITIAL_MEMORY=64MB', '-sMEMORY64=1', '-sUSE_ICU=1', '-sUSE_BOOST_HEADERS=1', '-sUSE_ZLIB=1', '-sUSE_BZIP2=1', '-fexceptions']
46+
tools.build:sharedlinkflags=['-sALLOW_MEMORY_GROWTH=1', '-sMAXIMUM_MEMORY=4GB', '-sINITIAL_MEMORY=64MB', '-sMEMORY64=1', '-sUSE_ICU=1', '-sUSE_BOOST_HEADERS=1', '-sUSE_ZLIB=1', '-sUSE_BZIP2=1', '-fexceptions']
47+
boost/*:tools.build:cxxflags=['-sMEMORY64=1']

src/ServerMain.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ int main(int argc, char** argv) {
5353
bool noPatterns;
5454
bool onlyPsoAndPosPermutations;
5555
bool persistUpdates;
56+
std::vector<std::string> preloadMaterializedViews;
5657

5758
ad_utility::MemorySize memoryMaxSize;
5859

@@ -176,6 +177,11 @@ int main(int argc, char** argv) {
176177
&RuntimeParameters::materializedViewWriterMemory_>(),
177178
"Memory limit for sorting rows during the writing of materialized "
178179
"views.");
180+
add("preload-materialized-views,l",
181+
po::value<std::vector<std::string>>(&preloadMaterializedViews)
182+
->multitoken(),
183+
"The names of materialized views to be loaded automatically on server "
184+
"start (this option takes an arbitrary number of arguments).");
179185
po::variables_map optionsMap;
180186

181187
try {
@@ -203,7 +209,7 @@ int main(int argc, char** argv) {
203209
Server server(port, numSimultaneousQueries, memoryMaxSize,
204210
std::move(accessToken), noAccessCheck, !noPatterns);
205211
server.run(indexBasename, text, !noPatterns, !onlyPsoAndPosPermutations,
206-
persistUpdates);
212+
persistUpdates, preloadMaterializedViews);
207213
} catch (const std::exception& e) {
208214
// This code should never be reached as all exceptions should be handled
209215
// within server.run()

src/engine/CartesianProductJoin.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
// Copyright 2023, University of Freiburg,
2-
// Chair of Algorithms and Data Structures.
3-
// Author: Johannes Kalmbach <[email protected]>
1+
// Copyright 2024 - 2026 The QLever Authors, in particular:
2+
//
3+
// 2023 - 2025 Johannes Kalmbach <[email protected]>, UFR
4+
// 2026 Hannah Bast <[email protected]>, UFR
5+
//
6+
// UFR = University of Freiburg, Chair of Algorithms and Data Structures
7+
8+
// You may not use this file except in compliance with the Apache 2.0 License,
9+
// which can be found in the `LICENSE` file at the root of the QLever project.
410

511
#include "engine/CartesianProductJoin.h"
612

@@ -360,7 +366,7 @@ CPP_template_def(typename R)(requires ql::ranges::range<R>) Result::LazyResult
360366
// _____________________________________________________________________________
361367
Result::LazyResult CartesianProductJoin::createLazyConsumer(
362368
LocalVocab staticMergedVocab,
363-
ql::span<const std::shared_ptr<const Result>> subresults,
369+
std::vector<std::shared_ptr<const Result>> subresults,
364370
std::shared_ptr<const Result> lazyResult) const {
365371
AD_CONTRACT_CHECK(lazyResult);
366372
std::vector<std::reference_wrapper<const IdTable>> idTables;
@@ -371,7 +377,8 @@ Result::LazyResult CartesianProductJoin::createLazyConsumer(
371377
auto get = [self = this, staticMergedVocab = std::move(staticMergedVocab),
372378
limit = getLimitOffset().limitOrDefault(),
373379
offset = getLimitOffset()._offset, idTables = std::move(idTables),
374-
lastTableOffset = size_t{0}, producedTableSize = size_t{0},
380+
subresults = std::move(subresults), lastTableOffset = size_t{0},
381+
producedTableSize = size_t{0},
375382
idTableOpt = std::optional<Result::IdTableVocabPair>{}](
376383
auto& idTableVocabPair) mutable {
377384
// These things have to be done after handling a single input, so we do them

src/engine/CartesianProductJoin.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
// Copyright 2023, University of Freiburg,
2-
// Chair of Algorithms and Data Structures.
3-
// Author: Johannes Kalmbach <[email protected]>
1+
// Copyright 2024 - 2026 The QLever Authors, in particular:
2+
//
3+
// 2023 - 2025 Johannes Kalmbach <[email protected]>, UFR
4+
// 2026 Hannah Bast <[email protected]>, UFR
5+
//
6+
// UFR = University of Freiburg, Chair of Algorithms and Data Structures
7+
8+
// You may not use this file except in compliance with the Apache 2.0 License,
9+
// which can be found in the `LICENSE` file at the root of the QLever project.
410

511
#ifndef QLEVER_SRC_ENGINE_CARTESIANPRODUCTJOIN_H
612
#define QLEVER_SRC_ENGINE_CARTESIANPRODUCTJOIN_H
@@ -132,7 +138,7 @@ class CartesianProductJoin : public Operation {
132138
// Similar to `produceTablesLazily` but can handle a single lazy result.
133139
Result::LazyResult createLazyConsumer(
134140
LocalVocab staticMergedVocab,
135-
ql::span<const std::shared_ptr<const Result>> subresults,
141+
std::vector<std::shared_ptr<const Result>> subresults,
136142
std::shared_ptr<const Result> lazyResult) const;
137143
};
138144

src/engine/ExportQueryExecutionTrees.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,22 @@ auto ExportQueryExecutionTrees::constructQueryResultToTriples(
270270
std::move(cancellationHandle));
271271
}
272272

273+
// _____________________________________________________________________________
274+
template <>
275+
STREAMABLE_GENERATOR_TYPE ExportQueryExecutionTrees::
276+
constructQueryResultToStream<ad_utility::MediaType::turtle>(
277+
const QueryExecutionTree& qet,
278+
const ad_utility::sparql_types::Triples& constructTriples,
279+
LimitOffsetClause limitAndOffset, std::shared_ptr<const Result> result,
280+
CancellationHandle cancellationHandle,
281+
[[maybe_unused]] STREAMABLE_YIELDER_TYPE streamableYielder) {
282+
result->logResultSize();
283+
[[maybe_unused]] uint64_t resultSize = 0;
284+
auto generator = constructQueryResultToTriples(
285+
qet, constructTriples, limitAndOffset, result, resultSize,
286+
std::move(cancellationHandle));
287+
}
288+
273289
// _____________________________________________________________________________
274290
InputRangeTypeErased<std::string>
275291
ExportQueryExecutionTrees::constructQueryResultBindingsToQLeverJSON(

src/engine/ExportQueryExecutionTrees.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,28 @@ class ExportQueryExecutionTrees {
251251
static ad_utility::InputRangeTypeErased<TableConstRefWithVocab> getIdTables(
252252
const Result& result);
253253

254+
// Generate the result in "blocks" and, when iterating over the generator
255+
// from beginning to end, return the total number of rows in the result
256+
// in `totalResultSize`.
257+
//
258+
// Blocks, where all rows are before OFFSET, are requested (and hence
259+
// computed), but skipped.
260+
//
261+
// Blocks, where at least one row is after OFFSET but before the effective
262+
// export limit (minimum of the LIMIT and the value of the `send` parameter),
263+
// are requested and yielded (together with the corresponding `LocalVocab`
264+
// and the range from that `IdTable` that belongs to the result).
265+
//
266+
// Blocks after the effective export limit until the LIMIT are requested, and
267+
// counted towards the `totalResultSize`, but not yielded.
268+
//
269+
// Blocks after the LIMIT are not even requested.
270+
public:
271+
static ad_utility::InputRangeTypeErased<TableWithRange> getRowIndices(
272+
const LimitOffsetClause& limitOffset, const Result& result,
273+
uint64_t& resutSizeTotal, uint64_t resultSizeMultiplicator = 1);
274+
275+
private:
254276
FRIEND_TEST(ExportQueryExecutionTrees, getIdTablesReturnsSingletonIterator);
255277
FRIEND_TEST(ExportQueryExecutionTrees, getIdTablesMirrorsGenerator);
256278
FRIEND_TEST(ExportQueryExecutionTrees, ensureCorrectSlicingOfSingleIdTable);

src/engine/MaterializedViews.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,9 @@ MaterializedViewWriter::RangeOfIdTables MaterializedViewWriter::getSortedBlocks(
244244
IndexMetaDataMmap MaterializedViewWriter::writePermutation(
245245
RangeOfIdTables sortedBlocksSPO) const {
246246
std::string spoFilename = getFilenameBase() + ".index.spo";
247-
CompressedRelationWriter spoWriter{
248-
numCols(),
249-
ad_utility::File{spoFilename, "w"},
250-
UNCOMPRESSED_BLOCKSIZE_COMPRESSED_METADATA_PER_COLUMN,
251-
};
247+
auto spoWriter = std::make_unique<CompressedRelationWriter>(
248+
numCols(), ad_utility::File{spoFilename, "w"},
249+
UNCOMPRESSED_BLOCKSIZE_COMPRESSED_METADATA_PER_COLUMN);
252250

253251
qlever::KeyOrder spoKeyOrder{0, 1, 2, 3};
254252
IndexMetaDataMmap spoMetaData;
@@ -262,7 +260,7 @@ IndexMetaDataMmap MaterializedViewWriter::writePermutation(
262260

263261
auto [numDistinctPredicates, blockData] =
264262
CompressedRelationWriter::createPermutation(
265-
{spoWriter, spoCallback},
263+
{std::move(spoWriter), spoCallback},
266264
ad_utility::InputRangeTypeErased{std::move(sortedBlocksSPO)},
267265
spoKeyOrder, {});
268266

0 commit comments

Comments
 (0)