Skip to content

Commit 1d590ef

Browse files
committed
support redis call
1 parent d0778c1 commit 1d590ef

File tree

15 files changed

+451
-33
lines changed

15 files changed

+451
-33
lines changed

.bazelrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
build:compdb --build_tag_filters=-nocompdb
12
# Pass CC, CXX and PATH from the environment.
23
build --action_env=CC
34
build --action_env=CXX

WORKSPACE

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ load("@proxy_wasm_cpp_host//bazel:dependencies.bzl", "proxy_wasm_cpp_host_depend
88

99
proxy_wasm_cpp_host_dependencies()
1010

11-
load("@proxy_wasm_cpp_sdk//bazel:repositories.bzl", "proxy_wasm_cpp_sdk_repositories")
11+
load("@proxy_wasm_cpp_sdk//bazel:repositories.bzl", "proxy_wasm_cpp_host_repositories")
1212

13-
proxy_wasm_cpp_sdk_repositories()
13+
proxy_wasm_cpp_host_repositories()
1414

15-
load("@proxy_wasm_cpp_sdk//bazel:dependencies.bzl", "proxy_wasm_cpp_sdk_dependencies")
15+
load("@proxy_wasm_cpp_sdk//bazel:dependencies.bzl", "proxy_wasm_cpp_host_dependencies")
1616

17-
proxy_wasm_cpp_sdk_dependencies()
17+
proxy_wasm_cpp_host_dependencies()
1818

19-
load("@proxy_wasm_cpp_sdk//bazel:dependencies_extra.bzl", "proxy_wasm_cpp_sdk_dependencies_extra")
19+
load("@proxy_wasm_cpp_sdk//bazel:dependencies_extra.bzl", "proxy_wasm_cpp_host_dependencies_extra")
2020

21-
proxy_wasm_cpp_sdk_dependencies_extra()
21+
proxy_wasm_cpp_host_dependencies_extra()

bazel/repositories.bzl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
1919
def proxy_wasm_cpp_host_repositories():
2020
# Bazel extensions.
2121

22+
maybe(
23+
http_archive,
24+
name = "bazel_compdb",
25+
strip_prefix = "bazel-compilation-database-0.5.2",
26+
url = "https://github.com/grailbio/bazel-compilation-database/archive/0.5.2.tar.gz",
27+
)
28+
2229
maybe(
2330
http_archive,
2431
name = "bazel_skylib",
@@ -94,11 +101,10 @@ def proxy_wasm_cpp_host_repositories():
94101
)
95102

96103
maybe(
97-
http_archive,
104+
git_repository,
98105
name = "proxy_wasm_cpp_sdk",
99-
sha256 = "89792fc1abca331f29f99870476a04146de5e82ff903bdffca90e6729c1f2470",
100-
strip_prefix = "proxy-wasm-cpp-sdk-95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee",
101-
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee.tar.gz"],
106+
commit = "0a2b9e1928878e1662ad671be4ee9a8d0853243a",
107+
remote = "[email protected]:Ingress/proxy-wasm-cpp-sdk.git",
102108
)
103109

104110
# Test dependencies.

include/proxy-wasm/context.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class ContextBase : public RootInterface,
136136
public StreamInterface,
137137
public HeaderInterface,
138138
public HttpCallInterface,
139+
public RedisCallInterface,
139140
public GrpcCallInterface,
140141
public GrpcStreamInterface,
141142
public MetricsInterface,
@@ -151,6 +152,7 @@ class ContextBase : public RootInterface,
151152
virtual ~ContextBase();
152153

153154
WasmBase *wasm() const { return wasm_; }
155+
void clearWasm() { wasm_ = nullptr; }
154156
uint32_t id() const { return id_; }
155157
// The VM Context used for calling "malloc" has an id_ == 0.
156158
bool isVmContext() const { return id_ == 0; }
@@ -214,6 +216,10 @@ class ContextBase : public RootInterface,
214216
// Async call response.
215217
void onHttpCallResponse(HttpCallToken token, uint32_t headers, uint32_t body_size,
216218
uint32_t trailers) override;
219+
220+
// Redis
221+
void onRedisCallResponse(RedisCallToken token, uint32_t status, uint32_t response_size) override;
222+
217223
// Grpc
218224
void onGrpcReceiveInitialMetadata(GrpcToken token, uint32_t elements) override;
219225
void onGrpcReceive(GrpcToken token, uint32_t response_size) override;
@@ -276,6 +282,16 @@ class ContextBase : public RootInterface,
276282
return unimplemented();
277283
}
278284

285+
// Redis
286+
WasmResult redisInit(std::string_view /* target */, std::string_view /* username */,
287+
std::string_view /* password */, int /* timeout_millisconds */) override {
288+
return unimplemented();
289+
}
290+
WasmResult redisCall(std::string_view /* target */, std::string_view /* query */,
291+
uint32_t * /* token_ptr */) override {
292+
return unimplemented();
293+
}
294+
279295
// gRPC
280296
WasmResult grpcCall(std::string_view /* grpc_service */, std::string_view /* service_name */,
281297
std::string_view /* method_name */, const Pairs & /* initial_metadata */,

include/proxy-wasm/context_interface.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using GrpcToken = uint32_t;
3737
using GrpcStatusCode = uint32_t;
3838
using SharedQueueDequeueToken = uint32_t;
3939
using SharedQueueEnqueueToken = uint32_t;
40+
using RedisCallToken = uint32_t;
4041

4142
// TODO: update SDK and use this.
4243
enum class ProxyAction : uint32_t {
@@ -161,6 +162,12 @@ struct RootInterface : public RootGrpcInterface {
161162
*/
162163
virtual void onHttpCallResponse(HttpCallToken token, uint32_t headers, uint32_t body_size,
163164
uint32_t trailers) = 0;
165+
/**
166+
* Called on a Root Context when a response arrives for an outstanding redisCall().
167+
* @param token is the token returned by the corresponding redisCall().
168+
*/
169+
virtual void onRedisCallResponse(RedisCallToken token, uint32_t status,
170+
uint32_t response_size) = 0;
164171

165172
/**
166173
* Called on a Root Context when an Inter-VM shared queue message has arrived.
@@ -416,6 +423,14 @@ struct HttpCallInterface {
416423
int timeout_milliseconds, HttpCallToken *token_ptr) = 0;
417424
};
418425

426+
struct RedisCallInterface {
427+
virtual ~RedisCallInterface() = default;
428+
virtual WasmResult redisInit(std::string_view target, std::string_view username,
429+
std::string_view password, int timeout_milliseconds) = 0;
430+
virtual WasmResult redisCall(std::string_view target, std::string_view query,
431+
RedisCallToken *token_ptr) = 0;
432+
};
433+
419434
struct GrpcCallInterface {
420435
virtual ~GrpcCallInterface() = default;
421436
/**

include/proxy-wasm/exports.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ Word get_response_body_buffer_bytes(Word start, Word length, Word ptr_ptr, Word
104104
Word http_call(Word uri_ptr, Word uri_size, Word header_pairs_ptr, Word header_pairs_size,
105105
Word body_ptr, Word body_size, Word trailer_pairs_ptr, Word trailer_pairs_size,
106106
Word timeout_milliseconds, Word token_ptr);
107+
Word redis_init(Word service_ptr, Word service_size, Word username_ptr, Word username_size,
108+
Word passowrd_ptr, Word password_size, Word timeout_milliseconds);
109+
Word redis_call(Word service_ptr, Word service_size, Word query_ptr, Word query_size,
110+
Word token_ptr);
107111
Word define_metric(Word metric_type, Word name_ptr, Word name_size, Word metric_id_ptr);
108112
Word increment_metric(Word metric_id, int64_t offset);
109113
Word record_metric(Word metric_id, uint64_t value);
@@ -163,7 +167,8 @@ void emscripten_notify_memory_growth(Word);
163167
_f(get_current_time_nanoseconds) _f(define_metric) \
164168
_f(increment_metric) _f(record_metric) _f(get_metric) \
165169
_f(set_effective_context) _f(done) \
166-
_f(call_foreign_function)
170+
_f(call_foreign_function) _f(redis_init) \
171+
_f(redis_call)
167172

168173
#define FOR_ALL_HOST_FUNCTIONS_ABI_SPECIFIC(_f) \
169174
_f(get_configuration) _f(continue_request) _f(continue_response) _f(clear_route_cache) \

include/proxy-wasm/null_plugin.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class NullPlugin : public NullVmPlugin {
9292
void onHttpCallResponse(uint64_t context_id, uint64_t token, uint64_t headers, uint64_t body_size,
9393
uint64_t trailers);
9494

95+
void onRedisCallResponse(uint64_t context_id, uint64_t token, uint64_t status, uint64_t response);
96+
9597
void onGrpcReceive(uint64_t context_id, uint64_t token, size_t body_size);
9698
void onGrpcClose(uint64_t context_id, uint64_t token, uint64_t status_code);
9799
void onGrpcReceiveInitialMetadata(uint64_t context_id, uint64_t token, uint64_t headers);

include/proxy-wasm/wasm.h

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <string.h>
1919

20+
#include <cassert>
2021
#include <atomic>
2122
#include <deque>
2223
#include <map>
@@ -72,6 +73,11 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
7273
return it->second;
7374
return nullptr;
7475
}
76+
void clearWasmInContext() {
77+
for (auto &item : contexts_) {
78+
item.second->clearWasm();
79+
}
80+
}
7581
uint32_t allocContextId();
7682
bool isFailed() { return failed_ != FailState::Ok; }
7783
FailState fail_state() { return failed_; }
@@ -174,6 +180,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
174180
HttpCall = 0,
175181
GrpcCall = 1,
176182
GrpcStream = 2,
183+
RedisCall = 3,
177184
};
178185
static const uint32_t kCalloutTypeMask = 0x3; // Enough to cover the 3 types.
179186
static const uint32_t kCalloutIncrement = 0x4; // Enough to cover the 3 types.
@@ -186,6 +193,9 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
186193
bool isGrpcStreamId(uint32_t callout_id) {
187194
return (callout_id & kCalloutTypeMask) == static_cast<uint32_t>(CalloutType::GrpcStream);
188195
}
196+
bool isRedisCallId(uint32_t callout_id) {
197+
return (callout_id & kCalloutTypeMask) == static_cast<uint32_t>(CalloutType::RedisCall);
198+
}
189199
uint32_t nextHttpCallId() {
190200
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
191201
return next_http_call_id_ += kCalloutIncrement;
@@ -198,6 +208,10 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
198208
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
199209
return next_grpc_stream_id_ += kCalloutIncrement;
200210
}
211+
uint32_t nextRedisCallId() {
212+
// TODO(PiotrSikora): re-add rollover protection (requires at least 1 billion callouts).
213+
return next_redis_call_id_ += kCalloutIncrement;
214+
}
201215

202216
protected:
203217
friend class ContextBase;
@@ -257,6 +271,8 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
257271

258272
WasmCallVoid<5> on_http_call_response_;
259273

274+
WasmCallVoid<4> on_redis_call_response_;
275+
260276
WasmCallVoid<3> on_grpc_receive_;
261277
WasmCallVoid<3> on_grpc_close_;
262278
WasmCallVoid<3> on_grpc_create_initial_metadata_;
@@ -276,9 +292,10 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
276292
_f(on_downstream_connection_close) _f(on_upstream_connection_close) _f(on_request_body) \
277293
_f(on_request_trailers) _f(on_request_metadata) _f(on_response_body) \
278294
_f(on_response_trailers) _f(on_response_metadata) _f(on_http_call_response) \
279-
_f(on_grpc_receive) _f(on_grpc_close) _f(on_grpc_receive_initial_metadata) \
280-
_f(on_grpc_receive_trailing_metadata) _f(on_queue_ready) _f(on_done) \
281-
_f(on_log) _f(on_delete)
295+
_f(on_redis_call_response) _f(on_grpc_receive) _f(on_grpc_close) \
296+
_f(on_grpc_receive_initial_metadata) \
297+
_f(on_grpc_receive_trailing_metadata) _f(on_queue_ready) _f(on_done) \
298+
_f(on_log) _f(on_delete)
282299

283300
// Capabilities which are allowed to be linked to the module. If this is empty, restriction
284301
// is not enforced.
@@ -307,6 +324,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
307324
uint32_t next_http_call_id_ = static_cast<uint32_t>(CalloutType::HttpCall);
308325
uint32_t next_grpc_call_id_ = static_cast<uint32_t>(CalloutType::GrpcCall);
309326
uint32_t next_grpc_stream_id_ = static_cast<uint32_t>(CalloutType::GrpcStream);
327+
uint32_t next_redis_call_id_ = static_cast<uint32_t>(CalloutType::RedisCall);
310328

311329
// Actions to be done after the call into the VM returns.
312330
std::deque<std::function<void()>> after_vm_call_actions_;
@@ -335,8 +353,26 @@ class WasmHandleBase : public std::enable_shared_from_this<WasmHandleBase> {
335353

336354
std::shared_ptr<WasmBase> &wasm() { return wasm_base_; }
337355

356+
void setRecoverVmCallback(std::function<std::shared_ptr<WasmHandleBase>()> &&f) {
357+
recover_vm_callback_ = std::move(f);
358+
}
359+
360+
// Recover the wasm vm and generate a new wasm handle
361+
bool doRecover(std::shared_ptr<WasmHandleBase> &new_handle) {
362+
assert(new_handle == nullptr);
363+
if (recover_vm_callback_ == nullptr) {
364+
return true;
365+
}
366+
new_handle = recover_vm_callback_();
367+
if (!new_handle) {
368+
return false;
369+
}
370+
return true;
371+
}
372+
338373
protected:
339374
std::shared_ptr<WasmBase> wasm_base_;
375+
std::function<std::shared_ptr<WasmHandleBase>()> recover_vm_callback_;
340376
std::unordered_map<std::string, bool> plugin_canary_cache_;
341377
};
342378

@@ -365,10 +401,35 @@ class PluginHandleBase : public std::enable_shared_from_this<PluginHandleBase> {
365401

366402
std::shared_ptr<PluginBase> &plugin() { return plugin_; }
367403
std::shared_ptr<WasmBase> &wasm() { return wasm_handle_->wasm(); }
404+
std::shared_ptr<WasmHandleBase> &wasmHandle() { return wasm_handle_; }
405+
406+
void setRecoverPluginCallback(
407+
std::function<std::shared_ptr<PluginHandleBase>(std::shared_ptr<WasmHandleBase> &)> &&f) {
408+
recover_plugin_callback_ = std::move(f);
409+
}
410+
411+
// Recover the wasm plugin and generate a new plugin handle
412+
bool doRecover(std::shared_ptr<PluginHandleBase> &new_handle) {
413+
assert(new_handle == nullptr);
414+
if (recover_plugin_callback_ == nullptr) {
415+
return true;
416+
}
417+
std::shared_ptr<WasmHandleBase> new_wasm_handle;
418+
if (!wasm_handle_->doRecover(new_wasm_handle)) {
419+
return false;
420+
}
421+
new_handle = recover_plugin_callback_(new_wasm_handle);
422+
if (!new_handle) {
423+
return false;
424+
}
425+
return true;
426+
}
368427

369428
protected:
370429
std::shared_ptr<PluginBase> plugin_;
371430
std::shared_ptr<WasmHandleBase> wasm_handle_;
431+
std::function<std::shared_ptr<PluginHandleBase>(std::shared_ptr<WasmHandleBase> &)>
432+
recover_plugin_callback_;
372433
};
373434

374435
using PluginHandleFactory = std::function<std::shared_ptr<PluginHandleBase>(

include/proxy-wasm/wasm_api_impl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,23 @@ inline WasmResult proxy_http_call(const char *uri_ptr, size_t uri_size, void *he
211211
WR(trailer_pairs_ptr), WS(trailer_pairs_size),
212212
WS(timeout_milliseconds), WR(token_ptr)));
213213
}
214+
215+
// Redis
216+
// Returns token, used in callback onRedisCallResponse
217+
inline WasmResult proxy_redis_call(const char *service_ptr, size_t service_size,
218+
const char *query_ptr, size_t query_size, uint32_t *token_ptr) {
219+
return wordToWasmResult(exports::redis_call(WR(service_ptr), WS(service_size), WR(query_ptr),
220+
WS(query_size), WR(token_ptr)));
221+
}
222+
inline WasmResult proxy_redis_init(const char *service_ptr, size_t service_size,
223+
const char *username_ptr, size_t username_size,
224+
const char *password_ptr, size_t password_size,
225+
uint32_t timeout_milliseconds) {
226+
return wordToWasmResult(exports::redis_init(WR(service_ptr), WS(service_size), WR(username_ptr),
227+
WS(username_size), WR(password_ptr),
228+
WS(password_size), WS(timeout_milliseconds)));
229+
}
230+
214231
// gRPC
215232
// Returns token, used in gRPC callbacks (onGrpc...)
216233
inline WasmResult proxy_grpc_call(const char *service_ptr, size_t service_size,

include/proxy-wasm/wasm_vm.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ using WasmCallWord = std::function<WasmCallInFuncType<N, Word, ContextBase *, Wo
7070

7171
#define FOR_ALL_WASM_VM_EXPORTS(_f) \
7272
_f(proxy_wasm::WasmCallVoid<0>) _f(proxy_wasm::WasmCallVoid<1>) _f(proxy_wasm::WasmCallVoid<2>) \
73-
_f(proxy_wasm::WasmCallVoid<3>) _f(proxy_wasm::WasmCallVoid<5>) \
74-
_f(proxy_wasm::WasmCallWord<1>) _f(proxy_wasm::WasmCallWord<2>) \
75-
_f(proxy_wasm::WasmCallWord<3>)
73+
_f(proxy_wasm::WasmCallVoid<3>) _f(proxy_wasm::WasmCallVoid<4>) \
74+
_f(proxy_wasm::WasmCallVoid<5>) _f(proxy_wasm::WasmCallWord<1>) \
75+
_f(proxy_wasm::WasmCallWord<2>) _f(proxy_wasm::WasmCallWord<3>)
7676

7777
// These are templates and its helper for constructing signatures of functions callbacks from Wasm
7878
// VMs.
@@ -139,7 +139,13 @@ enum class Cloneable {
139139
InstantiatedModule // VMs can be cloned from an instantiated module.
140140
};
141141

142-
enum class AbiVersion { ProxyWasm_0_1_0, ProxyWasm_0_2_0, ProxyWasm_0_2_1, ProxyWasm_0_2_100, Unknown };
142+
enum class AbiVersion {
143+
ProxyWasm_0_1_0,
144+
ProxyWasm_0_2_0,
145+
ProxyWasm_0_2_1,
146+
ProxyWasm_0_2_100,
147+
Unknown
148+
};
143149

144150
class NullPlugin;
145151

@@ -174,6 +180,7 @@ enum class FailState : int {
174180
StartFailed = 5,
175181
ConfigureFailed = 6,
176182
RuntimeError = 7,
183+
RecoverError = 8,
177184
};
178185

179186
// Wasm VM instance. Provides the low level WASM interface.

0 commit comments

Comments
 (0)