Skip to content

Commit 1823d74

Browse files
DvirDukhanoshadmialonre24
authored
[MOD-5769] Open RedisJSON key with flags (RedisJSON#1095)
* wip * compile with redismodule-rs 2.0.5 * open key with flags * cargo fmt * redis 7.2 at circle * Bump json api version * Export shared api names using static lifetime * Update readies * Attemp fixing san failures * Attemp redismodule-rs from master * Bump dep redismodule-rs to 2.0.7 --------- Co-authored-by: Omer Shadmi <omer.shadmi@redis.com> Co-authored-by: alonre24 <alonreshef24@gmail.com>
1 parent ecede3c commit 1823d74

File tree

10 files changed

+136
-43
lines changed

10 files changed

+136
-43
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ commands:
7878
parameters:
7979
redis_version:
8080
type: string
81-
default: "7"
81+
default: "7.2"
8282
getredis_params:
8383
type: string
8484
default: ""

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@
3333
.settings/
3434

3535
wordlist.dic
36+
37+
venv/

Cargo.lock

+35-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

redis_json/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ ijson.workspace = true
2525
serde_json.workspace = true
2626
serde.workspace = true
2727
libc = "0.2"
28-
redis-module = "2.0"
28+
redis-module ={ version = "^2.0.7", default-features = false, features = ["min-redis-compatibility-version-7-2"] }
29+
redis-module-macros = "^2.0.7"
2930
itertools = "0.10"
3031
json_path = {path="../json_path"}
32+
linkme = "0.3"
3133

3234
[features]
3335
as-library = []

redis_json/src/c_api.rs

+58-28
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::key_value::KeyValue;
1818
use json_path::select_value::{SelectValue, SelectValueType};
1919
use json_path::{compile, create};
2020
use redis_module::raw as rawmod;
21-
use redis_module::{Context, RedisString, Status};
21+
use redis_module::{key::KeyFlags, Context, RedisString, Status};
2222

2323
use crate::manager::{Manager, ReadHolder};
2424

@@ -78,6 +78,21 @@ pub fn json_api_open_key_internal<M: Manager>(
7878
null()
7979
}
8080

81+
pub fn json_api_open_key_with_flags_internal<M: Manager>(
82+
manager: M,
83+
ctx: *mut rawmod::RedisModuleCtx,
84+
key: RedisString,
85+
flags: KeyFlags,
86+
) -> *const M::V {
87+
let ctx: Context = Context::new(ctx);
88+
if let Ok(h) = manager.open_key_read_with_flags(&ctx, &key, flags) {
89+
if let Ok(Some(v)) = h.get_value() {
90+
return v;
91+
}
92+
}
93+
null()
94+
}
95+
8196
pub fn json_api_get_at<M: Manager>(_: M, json: *const c_void, index: size_t) -> *const c_void {
8297
let json = unsafe { &*(json.cast::<M::V>()) };
8398
match json.get_type() {
@@ -313,6 +328,7 @@ macro_rules! redis_json_module_export_shared_api {
313328
pre_command_function: $pre_command_function_expr:expr,
314329
) => {
315330
use std::ptr::NonNull;
331+
use std::ffi::CString;
316332

317333
#[no_mangle]
318334
pub extern "C" fn JSONAPI_openKey(
@@ -326,6 +342,26 @@ macro_rules! redis_json_module_export_shared_api {
326342
)
327343
}
328344

345+
#[no_mangle]
346+
pub extern "C" fn JSONAPI_openKey_withFlags(
347+
ctx: *mut rawmod::RedisModuleCtx,
348+
key_str: *mut rawmod::RedisModuleString,
349+
flags: c_int,
350+
) -> *mut c_void {
351+
run_on_manager!(
352+
pre_command: ||$pre_command_function_expr(&get_llapi_ctx(), &Vec::new()),
353+
get_mngr: $get_manager_expr,
354+
run: |mngr| {
355+
json_api_open_key_with_flags_internal(
356+
mngr,
357+
ctx,
358+
RedisString::new(NonNull::new(ctx), key_str),
359+
KeyFlags::from_bits_truncate(flags as i32),
360+
) as *mut c_void
361+
},
362+
)
363+
}
364+
329365
#[no_mangle]
330366
#[allow(clippy::not_unsafe_ptr_arg_deref)]
331367
pub extern "C" fn JSONAPI_openKeyFromStr(
@@ -543,39 +579,24 @@ macro_rules! redis_json_module_export_shared_api {
543579
)
544580
}
545581

546-
static REDISJSON_GETAPI_V1: &str = concat!("RedisJSON_V1", "\0");
547-
static REDISJSON_GETAPI_V2: &str = concat!("RedisJSON_V2", "\0");
548-
static REDISJSON_GETAPI_V3: &str = concat!("RedisJSON_V3", "\0");
549-
static REDISJSON_GETAPI_V4: &str = concat!("RedisJSON_V4", "\0");
582+
// The apiname argument of export_shared_api should be a string literal with static lifetime
583+
static mut VEC_EXPORT_SHARED_API_NAME : Vec<CString> = Vec::new();
550584

551585
pub fn export_shared_api(ctx: &Context) {
552586
unsafe {
553587
LLAPI_CTX = Some(rawmod::RedisModule_GetThreadSafeContext.unwrap()(
554588
std::ptr::null_mut(),
555589
));
556-
ctx.export_shared_api(
557-
(&JSONAPI_CURRENT as *const RedisJSONAPI_CURRENT).cast::<c_void>(),
558-
REDISJSON_GETAPI_V1.as_ptr().cast::<c_char>(),
559-
);
560-
ctx.log_notice("Exported RedisJSON_V1 API");
561-
562-
ctx.export_shared_api(
563-
(&JSONAPI_CURRENT as *const RedisJSONAPI_CURRENT).cast::<c_void>(),
564-
REDISJSON_GETAPI_V2.as_ptr().cast::<c_char>(),
565-
);
566-
ctx.log_notice("Exported RedisJSON_V2 API");
567-
568-
ctx.export_shared_api(
569-
(&JSONAPI_CURRENT as *const RedisJSONAPI_CURRENT).cast::<c_void>(),
570-
REDISJSON_GETAPI_V3.as_ptr().cast::<c_char>(),
571-
);
572-
ctx.log_notice("Exported RedisJSON_V3 API");
573-
574-
ctx.export_shared_api(
575-
(&JSONAPI_CURRENT as *const RedisJSONAPI_CURRENT).cast::<c_void>(),
576-
REDISJSON_GETAPI_V4.as_ptr().cast::<c_char>(),
577-
);
578-
ctx.log_notice("Exported RedisJSON_V4 API");
590+
591+
for v in 1..6 {
592+
let version = format!("RedisJSON_V{}", v);
593+
VEC_EXPORT_SHARED_API_NAME.push(CString::new(version.as_str()).unwrap());
594+
ctx.export_shared_api(
595+
(&JSONAPI_CURRENT as *const RedisJSONAPI_CURRENT).cast::<c_void>(),
596+
VEC_EXPORT_SHARED_API_NAME[v-1].as_ptr().cast::<c_char>(),
597+
);
598+
ctx.log_notice(&format!("Exported {} API", version));
599+
}
579600
};
580601
}
581602

@@ -608,6 +629,8 @@ macro_rules! redis_json_module_export_shared_api {
608629
getKeyValues: JSONAPI_getKeyValues,
609630
nextKeyValue: JSONAPI_nextKeyValue,
610631
freeKeyValuesIter: JSONAPI_freeKeyValuesIter,
632+
// V5 entries
633+
openKeyWithFlags: JSONAPI_openKey_withFlags,
611634
};
612635

613636
#[repr(C)]
@@ -657,6 +680,13 @@ macro_rules! redis_json_module_export_shared_api {
657680
str: *mut *mut rawmod::RedisModuleString
658681
) -> *const c_void,
659682
pub freeKeyValuesIter: extern "C" fn(iter: *mut c_void),
683+
// V5
684+
pub openKeyWithFlags: extern "C" fn(
685+
ctx: *mut rawmod::RedisModuleCtx,
686+
key_str: *mut rawmod::RedisModuleString,
687+
flags: c_int,
688+
) -> *mut c_void,
689+
660690
}
661691
};
662692
}

redis_json/src/include/rejson_api.h

+7
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,15 @@ typedef struct RedisJSONAPI {
115115
// Free the iterator
116116
void (*freeKeyValuesIter)(JSONKeyValuesIterator iter);
117117

118+
////////////////
119+
// V5 entries //
120+
////////////////
121+
122+
RedisJSON (*openKeyWithFlags)(RedisModuleCtx *ctx, RedisModuleString *key_name, int flags);
123+
118124
} RedisJSONAPI;
119125

126+
#define RedisJSONAPI_LATEST_API_VER 5
120127
#ifdef __cplusplus
121128
}
122129
#endif

redis_json/src/ivalue_manager.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::REDIS_JSON_TYPE;
1313
use bson::decode_document;
1414
use ijson::object::Entry;
1515
use ijson::{DestructuredMut, INumber, IObject, IString, IValue, ValueType};
16-
use redis_module::key::{verify_type, RedisKey, RedisKeyWritable};
16+
use redis_module::key::{verify_type, KeyFlags, RedisKey, RedisKeyWritable};
1717
use redis_module::raw::{RedisModuleKey, Status};
1818
use redis_module::rediserror::RedisError;
1919
use redis_module::{Context, NotifyEvent, RedisResult, RedisString};
@@ -586,6 +586,16 @@ impl<'a> Manager for RedisIValueJsonKeyManager<'a> {
586586
Ok(IValueKeyHolderRead { key })
587587
}
588588

589+
fn open_key_read_with_flags(
590+
&self,
591+
ctx: &Context,
592+
key: &RedisString,
593+
flags: KeyFlags,
594+
) -> Result<Self::ReadHolder, RedisError> {
595+
let key = ctx.open_key_with_flags(key, flags);
596+
Ok(IValueKeyHolderRead { key })
597+
}
598+
589599
fn open_key_write(
590600
&self,
591601
ctx: &Context,

redis_json/src/lib.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ use redis_module::Status;
1818
#[cfg(not(feature = "as-library"))]
1919
use redis_module::{Context, RedisResult};
2020

21+
#[cfg(not(feature = "as-library"))]
22+
use redis_module::key::KeyFlags;
23+
2124
#[cfg(not(feature = "as-library"))]
2225
use crate::c_api::{
2326
get_llapi_ctx, json_api_free_iter, json_api_free_key_values_iter, json_api_get,
2427
json_api_get_at, json_api_get_boolean, json_api_get_double, json_api_get_int,
2528
json_api_get_json, json_api_get_json_from_iter, json_api_get_key_value, json_api_get_len,
2629
json_api_get_string, json_api_get_type, json_api_is_json, json_api_len, json_api_next,
27-
json_api_next_key_value, json_api_open_key_internal, json_api_reset_iter, LLAPI_CTX,
30+
json_api_next_key_value, json_api_open_key_internal, json_api_open_key_with_flags_internal,
31+
json_api_reset_iter, LLAPI_CTX,
2832
};
2933
use crate::redisjson::Format;
3034

@@ -75,6 +79,7 @@ pub static REDIS_JSON_TYPE: RedisType = RedisType::new(
7579
unlink2: None,
7680
copy2: None,
7781
mem_usage2: None,
82+
aux_save2: None,
7883
},
7984
);
8085
/////////////////////////////////////////////////////
@@ -109,11 +114,13 @@ macro_rules! redis_json_module_create {(
109114
info: $info_func:ident,
110115
) => {
111116

112-
use redis_module::{redis_module, RedisString};
117+
use redis_module::RedisString;
113118
use std::marker::PhantomData;
114119
use std::os::raw::{c_double, c_int, c_longlong};
115-
use redis_module::{raw as rawmod, LogLevel};
120+
use redis_module::raw as rawmod;
121+
use redis_module::logging::RedisLogLevel;
116122
use rawmod::ModuleOptions;
123+
use redis_module::redis_module;
117124

118125
use std::{
119126
ffi::CStr,
@@ -168,7 +175,7 @@ macro_rules! redis_json_module_create {(
168175

169176
fn json_init_config(ctx: &Context, args: &[RedisString]) -> Status{
170177
if args.len() % 2 != 0 {
171-
ctx.log(LogLevel::Warning, "RedisJson arguments must be key:value pairs");
178+
ctx.log(RedisLogLevel::Warning, "RedisJson arguments must be key:value pairs");
172179
return Status::Err;
173180
}
174181
let mut args_map = HashMap::<String, String>::new();

redis_json/src/manager.rs

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
use json_path::select_value::SelectValue;
8+
use redis_module::key::KeyFlags;
89
use serde_json::Number;
910

1011
use redis_module::raw::RedisModuleKey;
@@ -80,6 +81,12 @@ pub trait Manager {
8081
ctx: &Context,
8182
key: &RedisString,
8283
) -> Result<Self::ReadHolder, RedisError>;
84+
fn open_key_read_with_flags(
85+
&self,
86+
ctx: &Context,
87+
key: &RedisString,
88+
flags: KeyFlags,
89+
) -> Result<Self::ReadHolder, RedisError>;
8390
fn open_key_write(
8491
&self,
8592
ctx: &Context,

0 commit comments

Comments
 (0)