Skip to content

Commit 4f82bce

Browse files
author
Meir Shpilraien (Spielrein)
authored
Added config changes server event (#343)
Added config changes server event
1 parent 4eb77dc commit 4f82bce

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

examples/server_events.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use std::sync::atomic::{AtomicI64, Ordering};
33
use redis_module::{
44
redis_module, server_events::FlushSubevent, Context, RedisResult, RedisString, RedisValue,
55
};
6-
use redis_module_macros::flush_event_handler;
6+
use redis_module_macros::{config_changed_event_handler, flush_event_handler};
77

88
static NUM_FLUSHES: AtomicI64 = AtomicI64::new(0);
9+
static NUM_MAX_MEMORY_CONFIGURATION_CHANGES: AtomicI64 = AtomicI64::new(0);
910

1011
#[flush_event_handler]
1112
fn flushed_event_handler(_ctx: &Context, flush_event: FlushSubevent) {
@@ -14,10 +15,24 @@ fn flushed_event_handler(_ctx: &Context, flush_event: FlushSubevent) {
1415
}
1516
}
1617

18+
#[config_changed_event_handler]
19+
fn config_changed_event_handler(_ctx: &Context, changed_configs: &[&str]) {
20+
changed_configs
21+
.iter()
22+
.find(|v| **v == "maxmemory")
23+
.map(|_| NUM_MAX_MEMORY_CONFIGURATION_CHANGES.fetch_add(1, Ordering::SeqCst));
24+
}
25+
1726
fn num_flushed(_ctx: &Context, _args: Vec<RedisString>) -> RedisResult {
1827
Ok(RedisValue::Integer(NUM_FLUSHES.load(Ordering::SeqCst)))
1928
}
2029

30+
fn num_maxmemory_changes(_ctx: &Context, _args: Vec<RedisString>) -> RedisResult {
31+
Ok(RedisValue::Integer(
32+
NUM_MAX_MEMORY_CONFIGURATION_CHANGES.load(Ordering::SeqCst),
33+
))
34+
}
35+
2136
//////////////////////////////////////////////////////
2237

2338
redis_module! {
@@ -27,5 +42,6 @@ redis_module! {
2742
data_types: [],
2843
commands: [
2944
["num_flushed", num_flushed, "readonly", 0, 0, 0],
45+
["num_max_memory_changes", num_maxmemory_changes, "readonly", 0, 0, 0],
3046
],
3147
}

redismodule-rs-macros/src/lib.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
8484
command::redis_command(attr, item)
8585
}
8686

87+
/// Proc macro which is set on a function that need to be called whenever the server role changes.
88+
/// The function must accept a [Context] and [ServerRole].
89+
///
90+
/// Example:
91+
///
92+
/// ```rust,no_run,ignore
93+
/// #[role_changed_event_handler]
94+
/// fn role_changed_event_handler(ctx: &Context, values: ServerRole) { ... }
95+
/// ```
8796
#[proc_macro_attribute]
8897
pub fn role_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
8998
let ast: ItemFn = match syn::parse(item) {
@@ -97,6 +106,15 @@ pub fn role_changed_event_handler(_attr: TokenStream, item: TokenStream) -> Toke
97106
gen.into()
98107
}
99108

109+
/// Proc macro which is set on a function that need to be called whenever a loading event happened.
110+
/// The function must accept a [Context] and [LoadingSubevent].
111+
///
112+
/// Example:
113+
///
114+
/// ```rust,no_run,ignore
115+
/// #[loading_event_handler]
116+
/// fn loading_event_handler(ctx: &Context, values: LoadingSubevent) { ... }
117+
/// ```
100118
#[proc_macro_attribute]
101119
pub fn loading_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
102120
let ast: ItemFn = match syn::parse(item) {
@@ -110,6 +128,15 @@ pub fn loading_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStre
110128
gen.into()
111129
}
112130

131+
/// Proc macro which is set on a function that need to be called whenever a flush event happened.
132+
/// The function must accept a [Context] and [FlushSubevent].
133+
///
134+
/// Example:
135+
///
136+
/// ```rust,no_run,ignore
137+
/// #[flush_event_handler]
138+
/// fn flush_event_handler(ctx: &Context, values: FlushSubevent) { ... }
139+
/// ```
113140
#[proc_macro_attribute]
114141
pub fn flush_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
115142
let ast: ItemFn = match syn::parse(item) {
@@ -123,6 +150,15 @@ pub fn flush_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream
123150
gen.into()
124151
}
125152

153+
/// Proc macro which is set on a function that need to be called whenever a module is loaded or unloaded on the server.
154+
/// The function must accept a [Context] and [ModuleChangeSubevent].
155+
///
156+
/// Example:
157+
///
158+
/// ```rust,no_run,ignore
159+
/// #[module_changed_event_handler]
160+
/// fn module_changed_event_handler(ctx: &Context, values: ModuleChangeSubevent) { ... }
161+
/// ```
126162
#[proc_macro_attribute]
127163
pub fn module_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
128164
let ast: ItemFn = match syn::parse(item) {
@@ -136,6 +172,29 @@ pub fn module_changed_event_handler(_attr: TokenStream, item: TokenStream) -> To
136172
gen.into()
137173
}
138174

175+
/// Proc macro which is set on a function that need to be called whenever a configuration change
176+
/// event is happening. The function must accept a [Context] and [&[&str]] that contains the names
177+
/// of the configiration values that was changed.
178+
///
179+
/// Example:
180+
///
181+
/// ```rust,no_run,ignore
182+
/// #[config_changed_event_handler]
183+
/// fn configuration_changed_event_handler(ctx: &Context, values: &[&str]) { ... }
184+
/// ```
185+
#[proc_macro_attribute]
186+
pub fn config_changed_event_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
187+
let ast: ItemFn = match syn::parse(item) {
188+
Ok(res) => res,
189+
Err(e) => return e.to_compile_error().into(),
190+
};
191+
let gen = quote! {
192+
#[linkme::distributed_slice(redis_module::server_events::CONFIG_CHANGED_SERVER_EVENTS_LIST)]
193+
#ast
194+
};
195+
gen.into()
196+
}
197+
139198
/// The macro auto generate a [From] implementation that can convert the struct into [RedisValue].
140199
///
141200
/// Example:

src/context/server_events.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ffi::CStr;
2+
13
use crate::raw;
24
use crate::{context::Context, RedisError};
35
use linkme::distributed_slice;
@@ -49,6 +51,9 @@ pub static FLUSH_SERVER_EVENTS_LIST: [fn(&Context, FlushSubevent)] = [..];
4951
#[distributed_slice()]
5052
pub static MODULE_CHANGED_SERVER_EVENTS_LIST: [fn(&Context, ModuleChangeSubevent)] = [..];
5153

54+
#[distributed_slice()]
55+
pub static CONFIG_CHANGED_SERVER_EVENTS_LIST: [fn(&Context, &[&str])] = [..];
56+
5257
extern "C" fn role_changed_callback(
5358
ctx: *mut raw::RedisModuleCtx,
5459
_eid: raw::RedisModuleEvent,
@@ -121,6 +126,36 @@ extern "C" fn module_change_event_callback(
121126
});
122127
}
123128

129+
extern "C" fn config_change_event_callback(
130+
ctx: *mut raw::RedisModuleCtx,
131+
_eid: raw::RedisModuleEvent,
132+
_subevent: u64,
133+
data: *mut ::std::os::raw::c_void,
134+
) {
135+
let data: &raw::RedisModuleConfigChange =
136+
unsafe { &*(data as *mut raw::RedisModuleConfigChange) };
137+
let config_names: Vec<_> = (0..data.num_changes)
138+
.into_iter()
139+
.map(|i| unsafe {
140+
let name = *data.config_names.offset(i as isize) as *mut i8;
141+
CStr::from_ptr(name)
142+
})
143+
.collect();
144+
let config_names: Vec<_> = config_names
145+
.iter()
146+
.map(|v| {
147+
v.to_str()
148+
.expect("Got a configuration name which is not a valid utf8")
149+
})
150+
.collect();
151+
let ctx = Context::new(ctx);
152+
CONFIG_CHANGED_SERVER_EVENTS_LIST
153+
.iter()
154+
.for_each(|callback| {
155+
callback(&ctx, config_names.as_slice());
156+
});
157+
}
158+
124159
fn register_single_server_event_type<T>(
125160
ctx: &Context,
126161
callbacks: &[fn(&Context, T)],
@@ -171,5 +206,11 @@ pub fn register_server_events(ctx: &Context) -> Result<(), RedisError> {
171206
raw::REDISMODULE_EVENT_MODULE_CHANGE,
172207
Some(module_change_event_callback),
173208
)?;
209+
register_single_server_event_type(
210+
ctx,
211+
&CONFIG_CHANGED_SERVER_EVENTS_LIST,
212+
raw::REDISMODULE_EVENT_CONFIG,
213+
Some(config_change_event_callback),
214+
)?;
174215
Ok(())
175216
}

tests/integration.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,24 @@ fn test_server_event() -> Result<()> {
393393

394394
assert_eq!(res, 2);
395395

396+
redis::cmd("config")
397+
.arg(&["set", "maxmemory", "1"])
398+
.query(&mut con)
399+
.with_context(|| "failed to run string.set")?;
400+
401+
let res: i64 = redis::cmd("num_max_memory_changes").query(&mut con)?;
402+
403+
assert_eq!(res, 1);
404+
405+
redis::cmd("config")
406+
.arg(&["set", "maxmemory", "0"])
407+
.query(&mut con)
408+
.with_context(|| "failed to run string.set")?;
409+
410+
let res: i64 = redis::cmd("num_max_memory_changes").query(&mut con)?;
411+
412+
assert_eq!(res, 2);
413+
396414
Ok(())
397415
}
398416

0 commit comments

Comments
 (0)