Skip to content

Commit

Permalink
Added configuration API. (#297)
Browse files Browse the repository at this point in the history
The PR adds the ability to add module configuration as using configuration API introduced on Redis 7: redis/redis#10285

The configuration is added optionally on `redis_module!` macro under `configurations` list that can contains the following subsections:

* `i64` configuration:
A list of `i64` configuration in the following format: `[<name>, <reference to the configuration object>, <default value>, <min value>, <max value>, <flags>, <optional on update callback>]`

* `string` configuration:
A list of `string` configuration in the following format: `[<name>, <reference to the configuration object>, <default value>, <flags>, <optional on update callback>]`

* `bool` configuration:
A list of `bool` configuration in the following format: `[<name>, <reference to the configuration object>, <default value>, <flags>, <optional on update callback>]`

* `enum` configuration:
A list of `enum` configuration in the following format: `[<name>, <reference to the configuration object>, <default value>, <flags>, <optional on update callback>]`

An example of all the 4 options can be found under `example/configuration.rs`. Notice that `enum` configuration is of special type and require provide an `enum` that implements the following traits: `TryFrom<i32>`, `From<$name>`, `EnumConfigurationValue`, `Clone`. User can use `enum_configuration` macro to easily added those implementation on a given `enum`.

In addition, it is also possible to tell redismodule-rs to look at the module arguments as if they were configuration using `module_args_as_configuration: true/false` option.

Usage examample:

```rust
/// A macro to easily creating an enum that can be used as an enum configuration
enum_configuration! {
    enum EnumConfiguration {
        Val1 = 1,
        Val2 = 2,
    }
}

/// Static variable that can be used as configuration and will be automatically set when `config set` command is used.
/// All the variables must be somehow thread safe protected, either as atomic variable, `RedisGILGuard` or `Mutex`.
lazy_static! {
    static ref CONFIGURATION_I64: RedisGILGuard<i64> = RedisGILGuard::default();
    static ref CONFIGURATION_ATOMIC_I64: AtomicI64 = AtomicI64::new(1);
    static ref CONFIGURATION_REDIS_STRING: RedisGILGuard<RedisString> =
        RedisGILGuard::new(RedisString::create(None, "default"));
    static ref CONFIGURATION_STRING: RedisGILGuard<String> = RedisGILGuard::new("default".into());
    static ref CONFIGURATION_MUTEX_STRING: Mutex<String> = Mutex::new("default".into());
    static ref CONFIGURATION_ATOMIC_BOOL: AtomicBool = AtomicBool::default();
    static ref CONFIGURATION_BOOL: RedisGILGuard<bool> = RedisGILGuard::default();
    static ref CONFIGURATION_ENUM: RedisGILGuard<EnumConfiguration> =
        RedisGILGuard::new(EnumConfiguration::Val1);
    static ref CONFIGURATION_MUTEX_ENUM: Mutex<EnumConfiguration> =
        Mutex::new(EnumConfiguration::Val1);
}

/// This function will be called when a configuration change is done and will count the total number of changes.
fn num_changes(ctx: &Context, _: Vec<RedisString>) -> RedisResult {
    let val = NUM_OF_CONFIGERATION_CHANGES.lock(ctx);
    Ok(RedisValue::Integer(*val))
}

/// The module initialisation macro, gets the configuration variable and some extra data (such as configuration name and
/// default value) and pass it to Redis so Redis will set them and return their values on `config set` and `config get` respectively.
redis_module! {
    name: "configuration",
    version: 1,
    data_types: [],
    commands: [
        ["configuration.num_changes", num_changes, "", 0, 0, 0],
    ],
    configurations: [
        i64: [
            ["i64", &*CONFIGURATION_I64, 10, 0, 1000, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
            ["atomic_i64", &*CONFIGURATION_ATOMIC_I64, 10, 0, 1000, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
        ],
        string: [
            ["redis_string", &*CONFIGURATION_REDIS_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
            ["string", &*CONFIGURATION_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed::<String, _>))],
            ["mutex_string", &*CONFIGURATION_MUTEX_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed::<String, _>))],
        ],
        bool: [
            ["atomic_bool", &*CONFIGURATION_ATOMIC_BOOL, true, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
            ["bool", &*CONFIGURATION_BOOL, true, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
        ],
        enum: [
            ["enum", &*CONFIGURATION_ENUM, EnumConfiguration::Val1, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
            ["enum_mutex", &*CONFIGURATION_MUTEX_ENUM, EnumConfiguration::Val1, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
        ],
        module_args_as_configuration: true, // Indication that we also want to read module arguments as configuration.
    ]
}
```
  • Loading branch information
MeirShpilraien authored Mar 26, 2023
1 parent 23bc513 commit deeb441
Show file tree
Hide file tree
Showing 16 changed files with 758 additions and 32 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ crate-type = ["cdylib"]
name = "string"
crate-type = ["cdylib"]

[[example]]
name = "configuration"
crate-type = ["cdylib"]

[[example]]
name = "acl"
crate-type = ["cdylib"]
Expand Down
82 changes: 82 additions & 0 deletions examples/configuration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#[macro_use]
extern crate redis_module;

use std::sync::{
atomic::{AtomicBool, AtomicI64},
Mutex,
};

use lazy_static::lazy_static;
use redis_module::{
configuration::{ConfigurationContext, ConfigurationFlags},
ConfigurationValue, Context, EnumConfigurationValue, RedisGILGuard, RedisResult, RedisString,
RedisValue,
};

enum_configuration! {
enum EnumConfiguration {
Val1 = 1,
Val2 = 2,
}
}

lazy_static! {
static ref NUM_OF_CONFIGURATION_CHANGES: RedisGILGuard<i64> = RedisGILGuard::default();
static ref CONFIGURATION_I64: RedisGILGuard<i64> = RedisGILGuard::default();
static ref CONFIGURATION_ATOMIC_I64: AtomicI64 = AtomicI64::new(1);
static ref CONFIGURATION_REDIS_STRING: RedisGILGuard<RedisString> =
RedisGILGuard::new(RedisString::create(None, "default"));
static ref CONFIGURATION_STRING: RedisGILGuard<String> = RedisGILGuard::new("default".into());
static ref CONFIGURATION_MUTEX_STRING: Mutex<String> = Mutex::new("default".into());
static ref CONFIGURATION_ATOMIC_BOOL: AtomicBool = AtomicBool::default();
static ref CONFIGURATION_BOOL: RedisGILGuard<bool> = RedisGILGuard::default();
static ref CONFIGURATION_ENUM: RedisGILGuard<EnumConfiguration> =
RedisGILGuard::new(EnumConfiguration::Val1);
static ref CONFIGURATION_MUTEX_ENUM: Mutex<EnumConfiguration> =
Mutex::new(EnumConfiguration::Val1);
}

fn on_configuration_changed<G, T: ConfigurationValue<G>>(
config_ctx: &ConfigurationContext,
_name: &str,
_val: &'static T,
) {
let mut val = NUM_OF_CONFIGURATION_CHANGES.lock(config_ctx);
*val += 1
}

fn num_changes(ctx: &Context, _: Vec<RedisString>) -> RedisResult {
let val = NUM_OF_CONFIGURATION_CHANGES.lock(ctx);
Ok(RedisValue::Integer(*val))
}

//////////////////////////////////////////////////////

redis_module! {
name: "configuration",
version: 1,
data_types: [],
commands: [
["configuration.num_changes", num_changes, "", 0, 0, 0],
],
configurations: [
i64: [
["i64", &*CONFIGURATION_I64, 10, 0, 1000, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
["atomic_i64", &*CONFIGURATION_ATOMIC_I64, 10, 0, 1000, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
],
string: [
["redis_string", &*CONFIGURATION_REDIS_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
["string", &*CONFIGURATION_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed::<String, _>))],
["mutex_string", &*CONFIGURATION_MUTEX_STRING, "default", ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed::<String, _>))],
],
bool: [
["atomic_bool", &*CONFIGURATION_ATOMIC_BOOL, true, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
["bool", &*CONFIGURATION_BOOL, true, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
],
enum: [
["enum", &*CONFIGURATION_ENUM, EnumConfiguration::Val1, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
["enum_mutex", &*CONFIGURATION_MUTEX_ENUM, EnumConfiguration::Val1, ConfigurationFlags::DEFAULT, Some(Box::new(on_configuration_changed))],
],
module_args_as_configuration: true,
]
}
3 changes: 2 additions & 1 deletion examples/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate redis_module;
use redis_module::{
Context, NotifyEvent, RedisError, RedisResult, RedisString, RedisValue, Status,
};
use std::ptr::NonNull;
use std::sync::atomic::{AtomicI64, Ordering};

static NUM_KEY_MISSES: AtomicI64 = AtomicI64::new(0);
Expand All @@ -25,7 +26,7 @@ fn event_send(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
return Err(RedisError::WrongArity);
}

let key_name = RedisString::create(ctx.ctx, "mykey");
let key_name = RedisString::create(NonNull::new(ctx.ctx), "mykey");
let status = ctx.notify_keyspace_event(NotifyEvent::GENERIC, "events.send", &key_name);
match status {
Status::Ok => Ok("Event sent".into()),
Expand Down
2 changes: 1 addition & 1 deletion examples/threads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct StaticData {
}

lazy_static! {
static ref STATIC_DATA: RedisGILGuard<StaticData> = RedisGILGuard::default();
static ref STATIC_DATA: RedisGILGuard<StaticData> = RedisGILGuard::new(StaticData::default());
}

fn set_static_data(ctx: &Context, args: Vec<RedisString>) -> RedisResult {
Expand Down
Loading

0 comments on commit deeb441

Please sign in to comment.