-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add BlankNode support for SERVICE (#1504)
With this commit, QLever supports to add new blank nodes during the evaluation of a query. This function is used to support blank nodes in the result of a `SERVICE` request. These blank nodes are distinct from all blank nodes in the index, and also from all blank nodes from other SERVICE request, eve if they came from the same server. This behavior is correct accordin to the SPARQL 1.1 federated query standard.
- Loading branch information
Showing
21 changed files
with
399 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright 2024, University of Freiburg, | ||
// Chair of Algorithms and Data Structures. | ||
// Author: Moritz Dom ([email protected]) | ||
|
||
#include "util/BlankNodeManager.h" | ||
|
||
namespace ad_utility { | ||
|
||
// _____________________________________________________________________________ | ||
BlankNodeManager::BlankNodeManager(uint64_t minIndex) | ||
: minIndex_(minIndex), | ||
randBlockIndex_( | ||
SlowRandomIntGenerator<uint64_t>(0, totalAvailableBlocks_ - 1)) {} | ||
|
||
// _____________________________________________________________________________ | ||
BlankNodeManager::Block BlankNodeManager::allocateBlock() { | ||
// The Random-Generation Algorithm's performance is reduced once the number of | ||
// used blocks exceeds a limit. | ||
auto numBlocks = usedBlocksSet_.rlock()->size(); | ||
AD_CORRECTNESS_CHECK( | ||
numBlocks < totalAvailableBlocks_ / 256, | ||
absl::StrCat("Critical high number of blank node blocks in use: ", | ||
numBlocks, " blocks")); | ||
|
||
auto usedBlocksSetPtr = usedBlocksSet_.wlock(); | ||
while (true) { | ||
auto blockIdx = randBlockIndex_(); | ||
if (!usedBlocksSetPtr->contains(blockIdx)) { | ||
usedBlocksSetPtr->insert(blockIdx); | ||
return Block(blockIdx, minIndex_ + blockIdx * blockSize_); | ||
} | ||
} | ||
} | ||
|
||
// _____________________________________________________________________________ | ||
BlankNodeManager::Block::Block(uint64_t blockIndex, uint64_t startIndex) | ||
: blockIdx_(blockIndex), nextIdx_(startIndex) {} | ||
|
||
// _____________________________________________________________________________ | ||
BlankNodeManager::LocalBlankNodeManager::LocalBlankNodeManager( | ||
BlankNodeManager* blankNodeManager) | ||
: blankNodeManager_(blankNodeManager) {} | ||
|
||
// _____________________________________________________________________________ | ||
BlankNodeManager::LocalBlankNodeManager::~LocalBlankNodeManager() { | ||
auto ptr = blankNodeManager_->usedBlocksSet_.wlock(); | ||
for (auto block : blocks_) { | ||
AD_CONTRACT_CHECK(ptr->contains(block.blockIdx_)); | ||
ptr->erase(block.blockIdx_); | ||
} | ||
} | ||
|
||
// _____________________________________________________________________________ | ||
uint64_t BlankNodeManager::LocalBlankNodeManager::getId() { | ||
if (blocks_.empty() || blocks_.back().nextIdx_ == idxAfterCurrentBlock_) { | ||
blocks_.emplace_back(blankNodeManager_->allocateBlock()); | ||
idxAfterCurrentBlock_ = blocks_.back().nextIdx_ + blockSize_; | ||
} | ||
return blocks_.back().nextIdx_++; | ||
} | ||
|
||
} // namespace ad_utility |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// Copyright 2024, University of Freiburg, | ||
// Chair of Algorithms and Data Structures. | ||
// Author: Moritz Dom ([email protected]) | ||
|
||
#pragma once | ||
|
||
#include <gtest/gtest_prod.h> | ||
|
||
#include <vector> | ||
|
||
#include "global/ValueId.h" | ||
#include "util/HashSet.h" | ||
#include "util/Random.h" | ||
#include "util/Synchronized.h" | ||
|
||
namespace ad_utility { | ||
/* | ||
* Manager class owned by an `Index` to manage currently available indices for | ||
* blank nodes to be added during runtime. The intention is to use the same | ||
* `BlankNodeIndex`-Datatype as for blank nodes given at indexing time, by | ||
* setting their count as the minimum index for the ones added at runtime. | ||
* A `LocalVocab` can register new blank nodes (e.g. resulting from a `Service` | ||
* operation) by obtaining a `Block` of currently unused indices using it's own | ||
* `LocalBlankNodeManager` from the `BlankNodeManager`. | ||
*/ | ||
class BlankNodeManager { | ||
public: | ||
// Minimum blank node index. | ||
const uint64_t minIndex_; | ||
|
||
// Number of indices that make up a single block. | ||
static constexpr uint blockSize_ = 1000; | ||
|
||
// Number of blocks available. | ||
const uint64_t totalAvailableBlocks_ = | ||
(ValueId::maxIndex - minIndex_ + 1) / blockSize_; | ||
|
||
private: | ||
// Int Generator yielding random block indices. | ||
SlowRandomIntGenerator<uint64_t> randBlockIndex_; | ||
|
||
// Tracks blocks currently used by instances of `LocalBlankNodeManager`. | ||
Synchronized<HashSet<uint64_t>> usedBlocksSet_; | ||
|
||
public: | ||
// Constructor, where `minIndex` is the minimum index such that all managed | ||
// indices are in [`minIndex_`, `ValueId::maxIndex`]. `minIndex_` is | ||
// determined by the number of BlankNodes in the current Index. | ||
explicit BlankNodeManager(uint64_t minIndex = 0); | ||
~BlankNodeManager() = default; | ||
|
||
// A BlankNodeIndex Block of size `blockSize_`. | ||
class Block { | ||
// Intentional private constructor, allowing only the BlankNodeManager to | ||
// create Blocks (for a `LocalBlankNodeManager`). | ||
explicit Block(uint64_t blockIndex, uint64_t startIndex); | ||
friend class BlankNodeManager; | ||
|
||
public: | ||
~Block() = default; | ||
// The index of this block. | ||
const uint64_t blockIdx_; | ||
// The next free index within this block. | ||
uint64_t nextIdx_; | ||
}; | ||
|
||
// Manages the BlankNodes used within a LocalVocab. | ||
class LocalBlankNodeManager { | ||
public: | ||
explicit LocalBlankNodeManager(BlankNodeManager* blankNodeManager); | ||
~LocalBlankNodeManager(); | ||
|
||
// No copy, as the managed blocks shall not be duplicated. | ||
LocalBlankNodeManager(const LocalBlankNodeManager&) = delete; | ||
LocalBlankNodeManager& operator=(const LocalBlankNodeManager&) = delete; | ||
|
||
LocalBlankNodeManager(LocalBlankNodeManager&&) = default; | ||
LocalBlankNodeManager& operator=(LocalBlankNodeManager&&) = default; | ||
|
||
// Get a new id. | ||
[[nodiscard]] uint64_t getId(); | ||
|
||
private: | ||
// Reserved blocks. | ||
std::vector<BlankNodeManager::Block> blocks_; | ||
|
||
// Reference of the BlankNodeManager, used to free the reserved blocks. | ||
BlankNodeManager* blankNodeManager_; | ||
|
||
// The first index after the current Block. | ||
uint64_t idxAfterCurrentBlock_{0}; | ||
|
||
FRIEND_TEST(BlankNodeManager, LocalBlankNodeManagerGetID); | ||
}; | ||
|
||
// Allocate and retrieve a block of free ids. | ||
[[nodiscard]] Block allocateBlock(); | ||
|
||
FRIEND_TEST(BlankNodeManager, blockAllocationAndFree); | ||
FRIEND_TEST(BlankNodeManager, moveLocalBlankNodeManager); | ||
}; | ||
|
||
} // namespace ad_utility |
Oops, something went wrong.