Skip to content

Commit eceb02d

Browse files
authored
Allow execution of multiple instances of the same plugin. (#92)
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
1 parent 4741d2f commit eceb02d

File tree

4 files changed

+156
-108
lines changed

4 files changed

+156
-108
lines changed

include/proxy-wasm/context.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,23 @@ struct PluginBase {
5050
std::string_view runtime, std::string_view plugin_configuration, bool fail_open)
5151
: name_(std::string(name)), root_id_(std::string(root_id)), vm_id_(std::string(vm_id)),
5252
runtime_(std::string(runtime)), plugin_configuration_(plugin_configuration),
53-
fail_open_(fail_open) {}
53+
fail_open_(fail_open), key_(root_id_ + "||" + plugin_configuration_) {}
5454

5555
const std::string name_;
5656
const std::string root_id_;
5757
const std::string vm_id_;
5858
const std::string runtime_;
59-
std::string plugin_configuration_;
59+
const std::string plugin_configuration_;
6060
const bool fail_open_;
61+
62+
const std::string &key() const { return key_; }
6163
const std::string &log_prefix() const { return log_prefix_; }
6264

6365
private:
6466
std::string makeLogPrefix() const;
6567

66-
std::string log_prefix_;
68+
const std::string key_;
69+
const std::string log_prefix_;
6770
};
6871

6972
struct BufferBase : public BufferInterface {
@@ -373,16 +376,16 @@ class ContextBase : public RootInterface,
373376
protected:
374377
friend class WasmBase;
375378

376-
void initializeRootBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin);
377379
std::string makeRootLogPrefix(std::string_view vm_id) const;
378380

379381
WasmBase *wasm_{nullptr};
380382
uint32_t id_{0};
381-
uint32_t parent_context_id_{0}; // 0 for roots and the general context.
382-
ContextBase *parent_context_{nullptr}; // set in all contexts.
383-
std::string root_id_; // set only in root context.
384-
std::string root_log_prefix_; // set only in root context.
385-
std::shared_ptr<PluginBase> plugin_;
383+
uint32_t parent_context_id_{0}; // 0 for roots and the general context.
384+
ContextBase *parent_context_{nullptr}; // set in all contexts.
385+
std::string root_id_; // set only in root context.
386+
std::string root_log_prefix_; // set only in root context.
387+
std::shared_ptr<PluginBase> plugin_; // set in root and stream contexts.
388+
std::shared_ptr<PluginBase> temp_plugin_; // Remove once ABI v0.1.0 is gone.
386389
bool in_vm_context_created_ = false;
387390
bool destroyed_ = false;
388391

include/proxy-wasm/wasm.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
5959
std::string_view vm_key() const { return vm_key_; }
6060
WasmVm *wasm_vm() const { return wasm_vm_.get(); }
6161
ContextBase *vm_context() const { return vm_context_.get(); }
62-
ContextBase *getRootContext(std::string_view root_id);
63-
ContextBase *getOrCreateRootContext(const std::shared_ptr<PluginBase> &plugin);
62+
ContextBase *getRootContext(const std::shared_ptr<PluginBase> &plugin, bool allow_closed);
6463
ContextBase *getContext(uint32_t id) {
6564
auto it = contexts_.find(id);
6665
if (it != contexts_.end())
@@ -78,6 +77,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
7877
void timerReady(uint32_t root_context_id);
7978
void queueReady(uint32_t root_context_id, uint32_t token);
8079

80+
void startShutdown(std::string_view plugin_key);
8181
void startShutdown();
8282
WasmResult done(ContextBase *root_context);
8383
void finishShutdown();
@@ -170,11 +170,12 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
170170
uint32_t next_context_id_ = 1; // 0 is reserved for the VM context.
171171
std::shared_ptr<ContextBase> vm_context_; // Context unrelated to any specific root or stream
172172
// (e.g. for global constructors).
173-
std::unordered_map<std::string, std::unique_ptr<ContextBase>> root_contexts_;
173+
std::unordered_map<std::string, std::unique_ptr<ContextBase>> root_contexts_; // Root contexts.
174+
std::unordered_map<std::string, std::unique_ptr<ContextBase>> pending_done_; // Root contexts.
175+
std::unordered_set<std::unique_ptr<ContextBase>> pending_delete_; // Root contexts.
174176
std::unordered_map<uint32_t, ContextBase *> contexts_; // Contains all contexts.
175177
std::unordered_map<uint32_t, std::chrono::milliseconds> timer_period_; // per root_id.
176178
std::unique_ptr<ShutdownHandle> shutdown_handle_;
177-
std::unordered_set<ContextBase *> pending_done_; // Root contexts not done during shutdown.
178179

179180
WasmCallVoid<0> _initialize_; /* Emscripten v1.39.17+ */
180181
WasmCallVoid<0> _start_; /* Emscripten v1.39.0+ */
@@ -275,11 +276,29 @@ createWasm(std::string vm_key, std::string code, std::shared_ptr<PluginBase> plu
275276
WasmHandleFactory factory, WasmHandleCloneFactory clone_factory, bool allow_precompiled);
276277
// Get an existing ThreadLocal VM matching 'vm_id' or nullptr if there isn't one.
277278
std::shared_ptr<WasmHandleBase> getThreadLocalWasm(std::string_view vm_id);
279+
280+
class PluginHandleBase : public std::enable_shared_from_this<PluginHandleBase> {
281+
public:
282+
explicit PluginHandleBase(std::shared_ptr<WasmHandleBase> wasm_handle,
283+
std::string_view plugin_key)
284+
: wasm_handle_(wasm_handle), plugin_key_(plugin_key) {}
285+
~PluginHandleBase() { wasm_handle_->wasm()->startShutdown(plugin_key_); }
286+
287+
std::shared_ptr<WasmBase> &wasm() { return wasm_handle_->wasm(); }
288+
289+
protected:
290+
std::shared_ptr<WasmHandleBase> wasm_handle_;
291+
std::string plugin_key_;
292+
};
293+
294+
using PluginHandleFactory = std::function<std::shared_ptr<PluginHandleBase>(
295+
std::shared_ptr<WasmHandleBase> base_wasm, std::string_view plugin_key)>;
296+
278297
// Get an existing ThreadLocal VM matching 'vm_id' or create one using 'base_wavm' by cloning or by
279298
// using it it as a template.
280-
std::shared_ptr<WasmHandleBase>
281-
getOrCreateThreadLocalWasm(std::shared_ptr<WasmHandleBase> base_wasm,
282-
std::shared_ptr<PluginBase> plugin, WasmHandleCloneFactory factory);
299+
std::shared_ptr<PluginHandleBase> getOrCreateThreadLocalPlugin(
300+
std::shared_ptr<WasmHandleBase> base_wasm, std::shared_ptr<PluginBase> plugin,
301+
WasmHandleCloneFactory clone_factory, PluginHandleFactory plugin_factory);
283302

284303
// Clear Base Wasm cache and the thread-local Wasm sandbox cache for the calling thread.
285304
void clearWasmCachesForTesting();

src/context.cc

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,10 @@ ContextBase::ContextBase(WasmBase *wasm) : wasm_(wasm), parent_context_(this) {
272272
wasm_->contexts_[id_] = this;
273273
}
274274

275-
ContextBase::ContextBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin) {
276-
initializeRootBase(wasm, plugin);
275+
ContextBase::ContextBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin)
276+
: wasm_(wasm), id_(wasm->allocContextId()), parent_context_(this), root_id_(plugin->root_id_),
277+
root_log_prefix_(makeRootLogPrefix(plugin->vm_id_)), plugin_(plugin) {
278+
wasm_->contexts_[id_] = this;
277279
}
278280

279281
// NB: wasm can be nullptr if it failed to be created successfully.
@@ -291,15 +293,6 @@ WasmVm *ContextBase::wasmVm() const { return wasm_->wasm_vm(); }
291293

292294
bool ContextBase::isFailed() { return !wasm_ || wasm_->isFailed(); }
293295

294-
void ContextBase::initializeRootBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin) {
295-
wasm_ = wasm;
296-
id_ = wasm->allocContextId();
297-
root_id_ = plugin->root_id_;
298-
root_log_prefix_ = makeRootLogPrefix(plugin->vm_id_);
299-
parent_context_ = this;
300-
wasm_->contexts_[id_] = this;
301-
}
302-
303296
std::string ContextBase::makeRootLogPrefix(std::string_view vm_id) const {
304297
std::string prefix;
305298
if (!root_id_.empty()) {
@@ -318,10 +311,10 @@ bool ContextBase::onStart(std::shared_ptr<PluginBase> plugin) {
318311
DeferAfterCallActions actions(this);
319312
bool result = true;
320313
if (wasm_->on_context_create_) {
321-
plugin_ = plugin;
314+
temp_plugin_ = plugin;
322315
wasm_->on_context_create_(this, id_, 0);
323316
in_vm_context_created_ = true;
324-
plugin_.reset();
317+
temp_plugin_.reset();
325318
}
326319
if (wasm_->on_vm_start_) {
327320
// Do not set plugin_ as the on_vm_start handler should be independent of the plugin since the
@@ -353,11 +346,11 @@ bool ContextBase::onConfigure(std::shared_ptr<PluginBase> plugin) {
353346
}
354347

355348
DeferAfterCallActions actions(this);
356-
plugin_ = plugin;
349+
temp_plugin_ = plugin;
357350
auto result =
358351
wasm_->on_configure_(this, id_, static_cast<uint32_t>(plugin->plugin_configuration_.size()))
359352
.u64_ != 0;
360-
plugin_.reset();
353+
temp_plugin_.reset();
361354
return result;
362355
}
363356

@@ -656,8 +649,8 @@ FilterMetadataStatus ContextBase::convertVmCallResultToFilterMetadataStatus(uint
656649
}
657650

658651
ContextBase::~ContextBase() {
659-
// Do not remove vm or root contexts which have the same lifetime as wasm_.
660-
if (parent_context_id_) {
652+
// Do not remove vm context which has the same lifetime as wasm_.
653+
if (id_) {
661654
wasm_->contexts_.erase(id_);
662655
}
663656
}

0 commit comments

Comments
 (0)