8#include <mutable/mutable-config.hpp>
20#include <unordered_map>
27template<
typename>
struct PlanTableBase;
28template<
typename Actual>
requires requires {
typename PlanTableBase<Actual>; }
struct PlanTableDecorator;
42 std::unique_ptr<DataModel>
model;
43 double cost = std::numeric_limits<double>::infinity();
45 std::unique_ptr<PlanTableEntryData>
data;
49 std::vector<Subproblem> s;
50 if (left) s.push_back(left);
51 if (right) s.push_back(right);
57 return (this->cost == other.
cost)
and (this->left == other.
left)
and (this->right == other.
right);
69template<
typename Actual>
125 auto &entry = operator[](left | right);
128 if (not entry.model) {
131 auto &entry_left = operator[](left);
132 auto &entry_right = operator[](right);
133 M_insist(
bool(entry_left.model),
"must have a model for the left side");
134 M_insist(
bool(entry_right.model),
"must have a model for the right side");
136 entry.model = CE.
estimate_join(G, *entry_left.model, *entry_right.model, condition);
143 if (rl_cost < cost) {
149 if (not has_plan(left | right) or cost < entry.cost) {
166 std::ostringstream oss;
171 void dump(std::ostream &out)
const { actual().dump(out); }
172 void dump()
const { actual().dump(); }
193 std::unique_ptr<PlanTableEntry[]> table_ =
nullptr;
208 , num_sources_(num_sources)
209 , num_additional_entries_(num_additional_entries)
210 , table_(allocator_.template make_unique<
PlanTableEntry[]>((1UL << num_sources) + num_additional_entries))
213 for (
auto ptr = &table_[0], end = &table_[size()]; ptr != end; ++ptr)
226 for (
auto ptr = &table_[0], end = &table_[size()]; ptr != end; ++ptr)
227 ptr->~PlanTableEntry();
229 allocator_.
dispose(std::move(table_), size());
235 if (this->num_sources() != other.
num_sources())
return false;
236 if (this->size() != other.
size())
return false;
239 if ((*
this)[S] != other[S])
return false;
246 size_type size()
const {
return (1UL << num_sources_) + num_additional_entries_; }
255 if (s.
size() == 1)
return true;
256 auto &e = operator[](s);
257 M_insist(e.left.empty() == e.right.empty(),
"either both sides are not set or both sides are set");
258 return not e.left.empty();
265 operator[](S).cost = std::numeric_limits<
decltype(PlanTableEntry::cost)>::infinity();
271 auto end() {
return &table_[size()]; }
276 void dump(std::ostream &out)
const;
291 std::unordered_map<Subproblem, PlanTableEntry, SubproblemHash>
table_;
302 : num_sources_(num_sources)
303 , table_(OnoLohmannCycle(num_sources_) + num_additional_entries)
315 if (this->num_sources() != other.
num_sources())
return false;
316 if (this->table_.size() != other.
table_.size())
return false;
317 for (
auto &this_e : this->table_) {
318 auto other_it = other.
table_.find(this_e.first);
319 if (other_it == other.
table_.end())
321 if (this_e.second != other_it->second)
340 if (s.
size() == 1)
return true;
341 if (
auto it = table_.find(s); it != table_.end()) {
342 auto &e = it->second;
343 M_insist(e.left.empty() == e.right.empty(),
"either both sides are not set or both sides are set");
344 return not e.left.empty();
351 for (
auto &entry : table_) {
352 if (not entry.first.is_singleton())
353 entry.second.cost = std::numeric_limits<
decltype(PlanTableEntry::cost)>::infinity();
364 void dump(std::ostream &out)
const;
372template<
typename Actual>
373requires requires {
typename PlanTableBase<Actual>; }
384 auto begin() {
return table_.begin(); }
385 auto end() {
return table_.end(); }
393template<
typename Actual>
396 swap(
static_cast<Actual&
>(first),
static_cast<Actual&
>(second));
400template<
typename Actual>
403 return out << static_cast<const Actual&>(PT);
and(sizeof(T)==4) U64x1 reinterpret_to_U64(m
uint64_t murmur3_64(uint64_t v)
This function implements the 64-bit finalizer of Murmur3_x64 by Austin Appleby, available at https://...
void swap(PlanTableBase< Actual > &first, PlanTableBase< Actual > &second)
M_LCOV_EXCL_START std::ostream & operator<<(std::ostream &out, const PlanTableBase< Actual > &PT)
virtual std::unique_ptr< DataModel > estimate_join(const QueryGraph &G, const DataModel &left, const DataModel &right, const cnf::CNF &condition) const =0
Form a new DataModel by joining two DataModels.
double calculate_join_cost(const QueryGraph &G, const PlanTable &PT, const CardinalityEstimator &CE, Subproblem left, Subproblem right, const cnf::CNF &condition) const
Returns the total cost of performing a Join operation.
friend std::ostream &M_EXPORT operator<<(std::ostream &out, const PlanTableBase &PT)
const PlanTableEntry & operator[](Subproblem s) const
Returns a reference to the entry of s.
bool has_plan(Subproblem s) const
Returns true iff the plan table has a plan for s.
friend void swap(PlanTableBase &first, PlanTableBase &second)
bool operator!=(const PlanTableBase &other) const
Returns true if two tables differ in at least one entry.
decltype(PlanTableEntry::cost) cost_type
void update(const QueryGraph &G, const CardinalityEstimator &CE, const CostFunction &CF, Subproblem left, Subproblem right, const cnf::CNF &condition)
Update the entry for left joined with right (left|right) by considering plan left join right.
bool operator==(const PlanTableBase &other) const
Returns true if two tables contain the exact same entries.
void reset_costs()
Resets the costs for all entries in the table.
const PlanTableEntry & at(Subproblem s) const
Returns a reference to the entry of s.
PlanTableEntry & at(Subproblem s)
Returns a reference to the entry of s.
cost_type c(Subproblem s) const
Returns the cost of the best plan to compute s.
friend std::string to_string(const PlanTableBase &PT)
PlanTableBase(const PlanTableBase &)=delete
PlanTableEntry & get_final()
Returns the entry for the final plan, i.e.
PlanTableBase(PlanTableBase &&other)
void dump(std::ostream &out) const
size_type num_sources() const
Returns the number of data sources.
PlanTableEntry & operator[](Subproblem s)
Returns a reference to the entry of s.
PlanTableBase & operator=(PlanTableBase other)
const PlanTableEntry & get_final() const
Returns the entry for the final plan, i.e.
PlanTableDecorator()=default
PlanTableDecorator(Actual &&table)
This interface allows for attaching arbitrary data to PlanTableEntry instances.
virtual ~PlanTableEntryData()
std::unique_ptr< PlanTableEntryData > data
additional data associated to this PlanTableEntry; used for holistic optimization
double cost
the cost of the subproblem
bool operator==(const PlanTableEntry &other) const
Returns true iff two entries are equal.
Subproblem left
the left subproblem
std::unique_ptr< DataModel > model
the model of this subplan's result
std::vector< Subproblem > get_subproblems() const
Subproblem right
the right subproblem
bool operator!=(const PlanTableEntry &other) const
Returns true iff two entries are not equal.
This table represents all explored plans with their sub-plans, estimated size, cost,...
size_type num_sources_
the number of DataSources in the query
friend std::ostream &M_EXPORT operator<<(std::ostream &out, const PlanTableLargeAndSparse &PT)
PlanTableLargeAndSparse()=default
PlanTableLargeAndSparse(const QueryGraph &G)
PlanTableLargeAndSparse(PlanTableLargeAndSparse &&other)
const PlanTableEntry & at(Subproblem s) const
size_type num_sources() const
PlanTableLargeAndSparse & operator=(PlanTableLargeAndSparse &&other)
static size_type OnoLohmannCycle(size_type N)
Computes the number of connected subgraphs (CSGs) of a query graph with N relations and cycle topolog...
const PlanTableEntry & operator[](Subproblem s) const
bool operator==(const PlanTableLargeAndSparse &other) const
bool operator!=(const PlanTableLargeAndSparse &other) const
std::unordered_map< Subproblem, PlanTableEntry, SubproblemHash > table_
the PlanTableEntrys
bool has_plan(Subproblem s) const
friend void swap(PlanTableLargeAndSparse &first, PlanTableLargeAndSparse &second)
PlanTableEntry & operator[](Subproblem s)
PlanTableLargeAndSparse(size_type num_sources, size_type num_additional_entries=0)
PlanTableEntry & at(Subproblem s)
PlanTableLargeAndSparse(const PlanTableLargeAndSparse &)=delete
This table represents all explored plans with their sub-plans, estimated size, cost,...
friend std::ostream &M_EXPORT operator<<(std::ostream &out, const PlanTableSmallOrDense &PT)
PlanTableEntry & operator[](Subproblem s)
PlanTableSmallOrDense(size_type num_sources, size_type num_additional_entries=0, allocator_type allocator=allocator_type())
size_type num_sources() const
PlanTableSmallOrDense(const PlanTableSmallOrDense &)=delete
PlanTableSmallOrDense(const QueryGraph &G, allocator_type allocator=allocator_type())
const PlanTableEntry & at(Subproblem s) const
bool operator==(const PlanTableSmallOrDense &other) const
bool operator!=(const PlanTableSmallOrDense &other) const
PlanTableSmallOrDense()=default
allocator_type allocator_
the allocator
size_type num_sources_
the number of DataSources in the query
PlanTableEntry & at(Subproblem s)
size_type num_additional_entries_
the number of additional entries this should contain
std::unique_ptr< PlanTableEntry[]> table_
the table of problem plans, sizes, and costs
bool has_plan(Subproblem s) const
const PlanTableEntry & operator[](Subproblem s) const
PlanTableSmallOrDense & operator=(PlanTableSmallOrDense &&other)
friend void swap(PlanTableSmallOrDense &first, PlanTableSmallOrDense &second)
PlanTableSmallOrDense(PlanTableSmallOrDense &&other)
The query graph represents all data sources and joins in a graph structure.
Implements a small and efficient set over integers in the range of 0 to 63 (including).
bool is_singleton() const
static SmallBitset All(std::size_t n)
Factory method for creating a SmallBitset with first n bits set.
std::size_t size() const
Returns the number of elements in this SmallBitset.
bool empty() const
Returns true if there are no elements in this SmallBitset.
std::size_t operator()(Subproblem S) const
void dispose(std::unique_ptr< T > ptr)
A CNF represents a conjunction of cnf::Clauses.
A helper class to define CRTP class hierarchies.
This allocator serves allocations using malloc/free.