Skip to content

Commit

Permalink
Merge branch 'ad-freiburg:master' into implement-apply-prefilter-expr…
Browse files Browse the repository at this point in the history
…essions
  • Loading branch information
realHannes authored Nov 21, 2024
2 parents 118ad87 + d53d4f9 commit f47cc2c
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 32 deletions.
4 changes: 3 additions & 1 deletion src/engine/LocalVocab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ BlankNodeIndex LocalVocab::getBlankNodeIndex(
AD_CONTRACT_CHECK(blankNodeManager);
// Initialize the `localBlankNodeManager_` if it doesn't exist yet.
if (!localBlankNodeManager_) [[unlikely]] {
localBlankNodeManager_.emplace(blankNodeManager);
localBlankNodeManager_ =
std::make_shared<ad_utility::BlankNodeManager::LocalBlankNodeManager>(
blankNodeManager);
}
return BlankNodeIndex::make(localBlankNodeManager_->getId());
}
Expand Down
24 changes: 23 additions & 1 deletion src/engine/LocalVocab.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

#pragma once

#include <algorithm>
#include <cstdlib>
#include <memory>
#include <ranges>
#include <span>
#include <string>
#include <vector>
Expand Down Expand Up @@ -48,7 +50,7 @@ class LocalVocab {

// Each `LocalVocab` has its own `LocalBlankNodeManager` to generate blank
// nodes when needed (e.g., when parsing the result of a SERVICE query).
std::optional<ad_utility::BlankNodeManager::LocalBlankNodeManager>
std::shared_ptr<ad_utility::BlankNodeManager::LocalBlankNodeManager>
localBlankNodeManager_;

public:
Expand Down Expand Up @@ -116,6 +118,26 @@ class LocalVocab {
*inserter = vocab.primaryWordSet_;
size_ += vocab.size_;
}

// Also merge the `vocabs` `LocalBlankNodeManager`s, if they exist.
using LocalBlankNodeManager =
ad_utility::BlankNodeManager::LocalBlankNodeManager;
auto localManagersView =
vocabs |
std::views::transform([](const LocalVocab& vocab) -> const auto& {
return vocab.localBlankNodeManager_;
});

auto it = std::ranges::find_if(localManagersView,
[](const auto& l) { return l != nullptr; });
if (it == localManagersView.end()) {
return;
}
if (!localBlankNodeManager_) {
localBlankNodeManager_ =
std::make_shared<LocalBlankNodeManager>((*it)->blankNodeManager());
}
localBlankNodeManager_->mergeWith(localManagersView);
}

// Create a new local vocab with empty set and other sets that are the union
Expand Down
30 changes: 15 additions & 15 deletions src/util/BlankNodeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "util/BlankNodeManager.h"

#include "util/Exception.h"

namespace ad_utility {

// _____________________________________________________________________________
Expand Down Expand Up @@ -41,30 +43,28 @@ BlankNodeManager::LocalBlankNodeManager::LocalBlankNodeManager(
BlankNodeManager* blankNodeManager)
: blankNodeManager_(blankNodeManager) {}

// _____________________________________________________________________________
BlankNodeManager::LocalBlankNodeManager::~LocalBlankNodeManager() {
auto ptr = blankNodeManager_->usedBlocksSet_.wlock();
for (const 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_;
if (blocks_->empty() || blocks_->back().nextIdx_ == idxAfterCurrentBlock_) {
blocks_->emplace_back(blankNodeManager_->allocateBlock());
idxAfterCurrentBlock_ = blocks_->back().nextIdx_ + blockSize_;
}
return blocks_.back().nextIdx_++;
return blocks_->back().nextIdx_++;
}

// _____________________________________________________________________________
bool BlankNodeManager::LocalBlankNodeManager::containsBlankNodeIndex(
uint64_t index) const {
return std::ranges::any_of(blocks_, [index](const Block& block) {
auto containsIndex = [index](const Block& block) {
return index >= block.startIdx_ && index < block.nextIdx_;
});
};

return std::ranges::any_of(*blocks_, containsIndex) ||
std::ranges::any_of(
otherBlocks_,
[&](const std::shared_ptr<const std::vector<Block>>& blocks) {
return std::ranges::any_of(*blocks, containsIndex);
});
}

} // namespace ad_utility
39 changes: 35 additions & 4 deletions src/util/BlankNodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class BlankNodeManager {

public:
~Block() = default;

// The index of this block.
const uint64_t blockIdx_;

Expand All @@ -71,7 +72,7 @@ class BlankNodeManager {
class LocalBlankNodeManager {
public:
explicit LocalBlankNodeManager(BlankNodeManager* blankNodeManager);
~LocalBlankNodeManager();
~LocalBlankNodeManager() = default;

// No copy, as the managed blocks should not be duplicated.
LocalBlankNodeManager(const LocalBlankNodeManager&) = delete;
Expand All @@ -87,16 +88,46 @@ class BlankNodeManager {
// Return true iff the `index` was returned by a previous call to `getId()`.
bool containsBlankNodeIndex(uint64_t index) const;

private:
// Reserved blocks.
std::vector<BlankNodeManager::Block> blocks_;
// Merge passed `LocalBlankNodeManager`s to keep alive their reserved
// BlankNodeIndex blocks.
template <std::ranges::range R>
void mergeWith(const R& localBlankNodeManagers) {
auto inserter = std::back_inserter(otherBlocks_);
for (const auto& l : localBlankNodeManagers) {
if (l == nullptr) {
continue;
}
std::ranges::copy(l->otherBlocks_, inserter);
*inserter = l->blocks_;
}
}

// Getter for the `blankNodeManager_` pointer required in
// `LocalVocab::mergeWith`.
BlankNodeManager* blankNodeManager() const { return blankNodeManager_; }

private:
// Reference to the BlankNodeManager, used to free the reserved blocks.
BlankNodeManager* blankNodeManager_;

// Reserved blocks.
using Blocks = std::vector<BlankNodeManager::Block>;
std::shared_ptr<Blocks> blocks_{
new Blocks(), [blankNodeManager = blankNodeManager()](auto blocksPtr) {
auto ptr = blankNodeManager->usedBlocksSet_.wlock();
for (const auto& block : *blocksPtr) {
AD_CONTRACT_CHECK(ptr->contains(block.blockIdx_));
ptr->erase(block.blockIdx_);
}
delete blocksPtr;
}};

// The first index after the current Block.
uint64_t idxAfterCurrentBlock_{0};

// Blocks merged from other `LocalBlankNodeManager`s.
std::vector<std::shared_ptr<const Blocks>> otherBlocks_;

FRIEND_TEST(BlankNodeManager, LocalBlankNodeManagerGetID);
};

Expand Down
30 changes: 19 additions & 11 deletions test/BlankNodeManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,32 @@ TEST(BlankNodeManager, blockAllocationAndFree) {
// _____________________________________________________________________________
TEST(BlankNodeManager, LocalBlankNodeManagerGetID) {
BlankNodeManager bnm(0);
BlankNodeManager::LocalBlankNodeManager l(&bnm);
auto l = std::make_shared<BlankNodeManager::LocalBlankNodeManager>(&bnm);

// initially the LocalBlankNodeManager doesn't have any blocks
EXPECT_EQ(l.blocks_.size(), 0);
EXPECT_EQ(l->blocks_->size(), 0);

// A new Block is allocated, if
// no blocks are allocated yet
uint64_t id = l.getId();
EXPECT_EQ(l.blocks_.size(), 1);
EXPECT_TRUE(l.containsBlankNodeIndex(id));
EXPECT_FALSE(l.containsBlankNodeIndex(id + 1));
EXPECT_FALSE(l.containsBlankNodeIndex(id - 1));
uint64_t id = l->getId();
EXPECT_EQ(l->blocks_->size(), 1);
EXPECT_TRUE(l->containsBlankNodeIndex(id));
EXPECT_FALSE(l->containsBlankNodeIndex(id + 1));
EXPECT_FALSE(l->containsBlankNodeIndex(id - 1));

// or the ids of the last block are all used
l.blocks_.back().nextIdx_ = id + BlankNodeManager::blockSize_;
id = l.getId();
EXPECT_TRUE(l.containsBlankNodeIndex(id));
EXPECT_EQ(l.blocks_.size(), 2);
l->blocks_->back().nextIdx_ = id + BlankNodeManager::blockSize_;
id = l->getId();
EXPECT_TRUE(l->containsBlankNodeIndex(id));
EXPECT_EQ(l->blocks_->size(), 2);

// The `LocalBlankNodeManager` still works when recursively merged.
std::vector itSelf{l};
l->mergeWith(itSelf);

EXPECT_TRUE(l->containsBlankNodeIndex(id));
EXPECT_TRUE(l->containsBlankNodeIndex(l->getId()));
EXPECT_EQ(l->blocks_, l->otherBlocks_[0]);
}

// _____________________________________________________________________________
Expand Down
32 changes: 32 additions & 0 deletions test/LocalVocabTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ TEST(LocalVocab, clone) {
for (size_t i = 0; i < inputWords.size(); ++i) {
EXPECT_EQ(*indices[i], inputWords[i]);
}

// Test that a BlankNodeIndex obtained by a `LocalVocab` is also contained
// in the clone.
ad_utility::BlankNodeManager bnm;
LocalVocab v;
auto id = v.getBlankNodeIndex(&bnm);
LocalVocab vClone = v.clone();
EXPECT_TRUE(vClone.isBlankNodeIndexContained(id));
}
// _____________________________________________________________________________
TEST(LocalVocab, merge) {
Expand Down Expand Up @@ -162,6 +170,30 @@ TEST(LocalVocab, merge) {
EXPECT_EQ(*indices[1], lit("twoA"));
EXPECT_EQ(*indices[2], lit("oneB"));
EXPECT_EQ(*indices[3], lit("twoB"));

// Test that the `LocalBlankNodeManager` of vocabs is merged correctly.
ad_utility::BlankNodeManager bnm;
LocalVocab localVocabMerged2;
BlankNodeIndex id;
{
LocalVocab vocC, vocD;
id = vocC.getBlankNodeIndex(&bnm);
auto vocabs2 = std::vector{&std::as_const(vocC), &std::as_const(vocD)};
localVocabMerged2 = LocalVocab::merge(vocabs2);
}
EXPECT_TRUE(localVocabMerged2.isBlankNodeIndexContained(id));

LocalVocab vocE, vocF;
auto id2 = vocE.getBlankNodeIndex(&bnm);
auto vocabs3 =
std::vector{&std::as_const(localVocabMerged2), &std::as_const(vocF)};
vocE.mergeWith(vocabs3 | std::views::transform(
[](const LocalVocab* l) -> const LocalVocab& {
return *l;
}));
EXPECT_TRUE(vocE.isBlankNodeIndexContained(id));
EXPECT_TRUE(localVocabMerged2.isBlankNodeIndexContained(id));
EXPECT_TRUE(vocE.isBlankNodeIndexContained(id2));
}

// _____________________________________________________________________________
Expand Down

0 comments on commit f47cc2c

Please sign in to comment.