Skip to content

Commit 7bbcc7c

Browse files
committed
[Catalog] Register Backends using factories.
1 parent 509c323 commit 7bbcc7c

File tree

7 files changed

+198
-133
lines changed

7 files changed

+198
-133
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#pragma once
2+
3+
#include <memory>
4+
#include <mutable/backend/Backend.hpp>
5+
#include <mutable/IR/Operator.hpp>
6+
#include <mutable/util/macro.hpp>
7+
#include <mutable/util/memory.hpp>
8+
#include <unordered_map>
9+
10+
11+
namespace m {
12+
13+
/** A `WasmPlatform` provides an environment to compile and execute WebAssembly modules. */
14+
struct WasmPlatform
15+
{
16+
/** the size of a WebAssembly memory page, 64 KiB. */
17+
static constexpr std::size_t WASM_PAGE_SIZE = 1UL << 16;
18+
/** The maximum memory of a WebAssembly module: 2^32 - 2^16 bytes ≈ 4 GiB */
19+
static constexpr std::size_t WASM_MAX_MEMORY = (1UL << 32) - (1UL << 16);
20+
/** The alignment that is suitable for all built-in types. */
21+
static constexpr std::size_t WASM_ALIGNMENT = 8;
22+
23+
/** A `WasmContext` holds associated information of a WebAssembly module instance. */
24+
struct WasmContext
25+
{
26+
enum config_t : uint64_t
27+
{
28+
TRAP_GUARD_PAGES = 0b1, ///< map guard pages with PROT_NONE to trap any accesses
29+
};
30+
31+
private:
32+
config_t config_;
33+
34+
public:
35+
unsigned id; ///< a unique ID
36+
const Operator &plan; ///< current plan
37+
memory::AddressSpace vm; ///< WebAssembly module instance's virtual address space aka.\ *linear memory*
38+
uint32_t heap = 0; ///< beginning of the heap, encoded as offset from the beginning of the virtual address space
39+
40+
WasmContext(uint32_t id, config_t configuration, const Operator &plan, std::size_t size);
41+
42+
bool config(config_t cfg) const { return bool(cfg & config_); }
43+
44+
/** Maps a table at the current start of `heap` and advances `heap` past the mapped region. Returns the address
45+
* (in linear memory) of the mapped table. Installs guard pages after each mapping. Acknowledges
46+
* `TRAP_GUARD_PAGES`. */
47+
uint32_t map_table(const Table &table);
48+
49+
/** Installs a guard page at the current `heap` and increments `heap` to the next page. Acknowledges
50+
* `TRAP_GUARD_PAGES`. */
51+
void install_guard_page();
52+
};
53+
54+
private:
55+
///> maps unique IDs to `WasmContext` instances
56+
static inline std::unordered_map<unsigned, std::unique_ptr<WasmContext>> contexts_;
57+
58+
public:
59+
/** Creates a new `WasmContext` with `size` bytes of virtual address space. */
60+
static WasmContext & Create_Wasm_Context_For_ID(unsigned id,
61+
WasmContext::config_t configuration = WasmContext::config_t(0x0),
62+
const Operator &plan = NoOpOperator(std::cout),
63+
std::size_t size = WASM_MAX_MEMORY)
64+
{
65+
auto wasm_context = std::make_unique<WasmContext>(id, configuration, plan, size);
66+
auto res = contexts_.emplace(id, std::move(wasm_context));
67+
M_insist(res.second, "WasmContext with that ID already exists");
68+
return *res.first->second;
69+
}
70+
71+
/** Disposes the `WasmContext` with ID `id`. */
72+
static void Dispose_Wasm_Context(unsigned id) {
73+
auto res = contexts_.erase(id);
74+
(void) res;
75+
M_insist(res == 1, "There is no context with the given ID to erase");
76+
}
77+
78+
/** Disposes the `WasmContext` `ctx`. */
79+
static void Dispose_Wasm_Context(const WasmContext &ctx) { Dispose_Wasm_Context(ctx.id); }
80+
81+
/** Returns a reference to the `WasmContext` with ID `id`. */
82+
static WasmContext & Get_Wasm_Context_By_ID(unsigned id) {
83+
auto it = contexts_.find(id);
84+
M_insist(it != contexts_.end(), "There is no context with the given ID");
85+
return *it->second;
86+
}
87+
88+
/** Tests if the `WasmContext` with ID `id` exists. */
89+
static bool Has_Wasm_Context(unsigned id) { return contexts_.find(id) != contexts_.end(); }
90+
91+
WasmPlatform() = default;
92+
virtual ~WasmPlatform() { }
93+
WasmPlatform(const WasmPlatform&) = delete;
94+
WasmPlatform(WasmPlatform&&) = default;
95+
96+
/** Compiles the given `plan` for this `WasmPlatform`. */
97+
virtual void compile(const Operator &plan) const = 0;
98+
99+
/** Executes the given `plan` on this `WasmPlatform`. */
100+
virtual void execute(const Operator &plan) = 0;
101+
};
102+
103+
/** A `Backend` to execute a plan on a specific `WasmPlatform`. */
104+
struct WasmBackend : Backend
105+
{
106+
private:
107+
std::unique_ptr<WasmPlatform> platform_; ///< the `WasmPlatform` of this backend
108+
109+
public:
110+
WasmBackend(std::unique_ptr<WasmPlatform> platform) : platform_(std::move(platform)) { }
111+
112+
/** Returns this backend's `WasmPlatform`. */
113+
const WasmPlatform & platform() const { return *platform_; }
114+
115+
/** Executes the given `plan` with this backend. */
116+
void execute(const Operator &plan) const override;
117+
};
118+
119+
}

include/mutable/catalog/Catalog.hpp

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <concepts>
44
#include <memory>
55
#include <mutable/backend/Backend.hpp>
6+
#include <mutable/backend/WebAssembly.hpp>
67
#include <mutable/catalog/CardinalityEstimator.hpp>
78
#include <mutable/catalog/CostFunction.hpp>
89
#include <mutable/catalog/DatabaseCommand.hpp>
@@ -54,6 +55,49 @@ struct ConcreteCardinalityEstimatorFactory : CardinalityEstimatorFactory
5455
}
5556
};
5657

58+
struct WasmPlatformFactory
59+
{
60+
virtual ~WasmPlatformFactory() { }
61+
62+
virtual std::unique_ptr<m::WasmPlatform> make() const = 0;
63+
};
64+
65+
template<typename T>
66+
requires std::derived_from<T, m::WasmPlatform>
67+
struct ConcreteWasmPlatformFactory : WasmPlatformFactory
68+
{
69+
std::unique_ptr<m::WasmPlatform> make() const override { return std::make_unique<T>(); }
70+
};
71+
72+
struct BackendFactory
73+
{
74+
virtual ~BackendFactory() { }
75+
76+
virtual std::unique_ptr<m::Backend> make() const = 0;
77+
};
78+
79+
template<typename T>
80+
requires std::derived_from<T, m::Backend>
81+
struct ConcreteBackendFactory : BackendFactory
82+
{
83+
std::unique_ptr<m::Backend> make() const override { return std::make_unique<T>(); }
84+
};
85+
86+
struct ConcreteWasmBackendFactory : BackendFactory
87+
{
88+
private:
89+
std::unique_ptr<WasmPlatformFactory> platform_factory_;
90+
91+
public:
92+
ConcreteWasmBackendFactory(std::unique_ptr<WasmPlatformFactory> platform_factory)
93+
: platform_factory_(std::move(platform_factory))
94+
{ }
95+
96+
std::unique_ptr<m::Backend> make() const override {
97+
return std::make_unique<m::WasmBackend>(platform_factory_->make());
98+
}
99+
};
100+
57101
struct DatabaseInstructionFactory
58102
{
59103
virtual ~DatabaseInstructionFactory() { }
@@ -271,7 +315,7 @@ struct M_EXPORT Catalog
271315
ComponentSet<storage::DataLayoutFactory> data_layouts_;
272316
ComponentSet<CardinalityEstimatorFactory> cardinality_estimators_;
273317
ComponentSet<PlanEnumerator> plan_enumerators_;
274-
ComponentSet<Backend> backends_;
318+
ComponentSet<BackendFactory> backends_;
275319
ComponentSet<CostFunction> cost_functions_;
276320
ComponentSet<DatabaseInstructionFactory> instructions_;
277321

@@ -390,17 +434,30 @@ struct M_EXPORT Catalog
390434

391435
/*===== Backends =================================================================================================*/
392436
/** Registers a new `Backend` with the given `name`. */
393-
void register_backend(const char *name, std::unique_ptr<Backend> backend, const char *description = nullptr) {
394-
backends_.add(pool(name), Component<Backend>(description, std::move(backend)));
437+
template<typename T>
438+
requires std::derived_from<T, m::Backend>
439+
void register_backend(const char *name, const char *description = nullptr) {
440+
auto c = Component<BackendFactory>(description, std::make_unique<ConcreteBackendFactory<T>>());
441+
backends_.add(pool(name), std::move(c));
442+
}
443+
/** Registers a new `WasmBackend` using the given `WasmPlatform` with the given `name`. */
444+
template<typename T>
445+
requires std::derived_from<T, m::WasmPlatform>
446+
void register_wasm_backend(const char *name, const char *description = nullptr) {
447+
auto c = Component<BackendFactory>(
448+
description,
449+
std::make_unique<ConcreteWasmBackendFactory>(std::make_unique<ConcreteWasmPlatformFactory<T>>())
450+
);
451+
backends_.add(pool(name), std::move(c));
395452
}
396453
/** Sets the default `Backend` to use. */
397454
void default_backend(const char *name) { backends_.set_default(pool(name)); }
398455
/** Returns `true` iff the `Catalog` has a default `Backend`. */
399456
bool has_default_backend() const { return backends_.has_default(); }
400-
/** Returns a reference to the default `Backend`. */
401-
Backend & backend() const { return backends_.get_default(); }
402-
/** Returns a reference to the `Backend` with the given `name`. */
403-
Backend & backend(const char *name) const { return backends_.get(pool(name)); }
457+
/** Returns a new `Backend`. */
458+
std::unique_ptr<Backend> create_backend() const { return backends_.get_default().make(); }
459+
/** Returns a new `Backend` of name `name`. */
460+
std::unique_ptr<Backend> create_backend(const char *name) const { return backends_.get(pool(name)).make(); }
404461
/** Returns the name of the default `Backend`. */
405462
const char * default_backend_name() const { return backends_.get_default_name(); }
406463

src/backend/Interpreter.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,9 +1520,5 @@ __attribute__((constructor(202)))
15201520
static void register_interpreter()
15211521
{
15221522
Catalog &C = Catalog::Get();
1523-
C.register_backend(
1524-
"Interpreter",
1525-
std::make_unique<Interpreter>(),
1526-
"tuple-at-a-time Interpreter built with virtual stack machines"
1527-
);
1523+
C.register_backend<Interpreter>("Interpreter", "tuple-at-a-time Interpreter built with virtual stack machines");
15281524
}

src/backend/V8Platform.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -836,11 +836,7 @@ __attribute__((constructor(202)))
836836
static void register_WasmV8()
837837
{
838838
Catalog &C = Catalog::Get();
839-
C.register_backend(
840-
"WasmV8",
841-
std::make_unique<WasmBackend>(as<WasmPlatform>(std::make_unique<V8Platform>())),
842-
"WebAssembly backend using Google's V8 engine"
843-
);
839+
C.register_wasm_backend<V8Platform>("WasmV8", "WebAssembly backend using Google's V8 engine");
844840

845841
/*----- Command-line arguments -----------------------------------------------------------------------------------*/
846842
C.arg_parser().add<int>(

src/backend/WebAssembly.hpp

Lines changed: 1 addition & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
#pragma once
22

3-
#include <memory>
4-
#include <mutable/backend/Backend.hpp>
5-
#include <mutable/IR/Operator.hpp>
6-
#include <mutable/util/macro.hpp>
7-
#include <mutable/util/memory.hpp>
8-
#include <unordered_map>
3+
#include <mutable/backend/WebAssembly.hpp>
94

105

116
/* Forward declaration of Binaryen classes. */
@@ -46,110 +41,4 @@ struct WasmModule
4641
void dump() const;
4742
};
4843

49-
/** A `WasmPlatform` provides an environment to compile and execute WebAssembly modules. */
50-
struct WasmPlatform
51-
{
52-
/** the size of a WebAssembly memory page, 64 KiB. */
53-
static constexpr std::size_t WASM_PAGE_SIZE = 1UL << 16;
54-
/** The maximum memory of a WebAssembly module: 2^32 - 2^16 bytes ≈ 4 GiB */
55-
static constexpr std::size_t WASM_MAX_MEMORY = (1UL << 32) - (1UL << 16);
56-
/** The alignment that is suitable for all built-in types. */
57-
static constexpr std::size_t WASM_ALIGNMENT = 8;
58-
59-
/** A `WasmContext` holds associated information of a WebAssembly module instance. */
60-
struct WasmContext
61-
{
62-
enum config_t : uint64_t
63-
{
64-
TRAP_GUARD_PAGES = 0b1, ///< map guard pages with PROT_NONE to trap any accesses
65-
};
66-
67-
private:
68-
config_t config_;
69-
70-
public:
71-
unsigned id; ///< a unique ID
72-
const Operator &plan; ///< current plan
73-
memory::AddressSpace vm; ///< WebAssembly module instance's virtual address space aka.\ *linear memory*
74-
uint32_t heap = 0; ///< beginning of the heap, encoded as offset from the beginning of the virtual address space
75-
76-
WasmContext(uint32_t id, config_t configuration, const Operator &plan, std::size_t size);
77-
78-
bool config(config_t cfg) const { return bool(cfg & config_); }
79-
80-
/** Maps a table at the current start of `heap` and advances `heap` past the mapped region. Returns the address
81-
* (in linear memory) of the mapped table. Installs guard pages after each mapping. Acknowledges
82-
* `TRAP_GUARD_PAGES`. */
83-
uint32_t map_table(const Table &table);
84-
85-
/** Installs a guard page at the current `heap` and increments `heap` to the next page. Acknowledges
86-
* `TRAP_GUARD_PAGES`. */
87-
void install_guard_page();
88-
};
89-
90-
private:
91-
///> maps unique IDs to `WasmContext` instances
92-
static inline std::unordered_map<unsigned, std::unique_ptr<WasmContext>> contexts_;
93-
94-
public:
95-
/** Creates a new `WasmContext` with `size` bytes of virtual address space. */
96-
static WasmContext & Create_Wasm_Context_For_ID(unsigned id,
97-
WasmContext::config_t configuration = WasmContext::config_t(0x0),
98-
const Operator &plan = NoOpOperator(std::cout),
99-
std::size_t size = WASM_MAX_MEMORY)
100-
{
101-
auto wasm_context = std::make_unique<WasmContext>(id, configuration, plan, size);
102-
auto res = contexts_.emplace(id, std::move(wasm_context));
103-
M_insist(res.second, "WasmContext with that ID already exists");
104-
return *res.first->second;
105-
}
106-
107-
/** Disposes the `WasmContext` with ID `id`. */
108-
static void Dispose_Wasm_Context(unsigned id) {
109-
auto res = contexts_.erase(id);
110-
(void) res;
111-
M_insist(res == 1, "There is no context with the given ID to erase");
112-
}
113-
114-
/** Disposes the `WasmContext` `ctx`. */
115-
static void Dispose_Wasm_Context(const WasmContext &ctx) { Dispose_Wasm_Context(ctx.id); }
116-
117-
/** Returns a reference to the `WasmContext` with ID `id`. */
118-
static WasmContext & Get_Wasm_Context_By_ID(unsigned id) {
119-
auto it = contexts_.find(id);
120-
M_insist(it != contexts_.end(), "There is no context with the given ID");
121-
return *it->second;
122-
}
123-
124-
/** Tests if the `WasmContext` with ID `id` exists. */
125-
static bool Has_Wasm_Context(unsigned id) { return contexts_.find(id) != contexts_.end(); }
126-
127-
WasmPlatform() = default;
128-
virtual ~WasmPlatform() { }
129-
WasmPlatform(const WasmPlatform&) = delete;
130-
WasmPlatform(WasmPlatform&&) = default;
131-
132-
/** Compiles the given `plan` for this `WasmPlatform`. */
133-
virtual void compile(const Operator &plan) const = 0;
134-
135-
/** Compiles the given `plan` to a `WasmModule` and executes it on this `WasmPlatform`. */
136-
virtual void execute(const Operator &plan) = 0;
137-
};
138-
139-
/** A `Backend` to execute a plan on a specific `WasmPlatform`. */
140-
struct WasmBackend : Backend
141-
{
142-
private:
143-
std::unique_ptr<WasmPlatform> platform_; ///< the `WasmPlatform` of this backend
144-
145-
public:
146-
WasmBackend(std::unique_ptr<WasmPlatform> platform) : platform_(std::move(platform)) { }
147-
148-
/** Returns this backend's `WasmPlatform`. */
149-
const WasmPlatform & platform() const { return *platform_; }
150-
151-
/** Executes the given `plan` with this backend. */
152-
void execute(const Operator &plan) const override;
153-
};
154-
15544
}

src/catalog/DatabaseCommand.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ void QueryDatabase::execute(Diagnostic &diag)
9494
if (Options::Get().dryrun)
9595
return;
9696

97-
M_TIME_EXPR(C.backend().execute(*logical_plan_), "Execute query", C.timer());
97+
static thread_local std::unique_ptr<Backend> backend;
98+
if (not backend)
99+
backend = M_TIME_EXPR(C.create_backend(), "Create backend", C.timer());
100+
M_TIME_EXPR(backend->execute(*logical_plan_), "Execute query", C.timer());
98101
}
99102

100103
void InsertRecords::execute(Diagnostic&)

0 commit comments

Comments
 (0)