Skip to content

Commit cf6b460

Browse files
committed
WIP
1 parent 334e2ff commit cf6b460

File tree

9 files changed

+175
-436
lines changed

9 files changed

+175
-436
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ libc = "0.2"
2222
time = "0.1"
2323
enum-primitive-derive = "^0.1"
2424
num-traits = "^0.1"
25-
failure = "0.1"
25+
#failure = "0.1"
2626

2727
[build-dependencies]
2828
bindgen = "0.47"

examples/data_type.rs

Lines changed: 49 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -1,232 +1,84 @@
1-
/*
2-
use std::os::raw::c_void;
3-
4-
extern crate libc;
5-
6-
use libc::c_int;
7-
1+
#[macro_use]
82
extern crate redismodule;
93

10-
use redismodule::error::Error;
11-
use redismodule::CommandOld;
12-
use redismodule::raw;
13-
use redismodule::Context;
14-
use redismodule::raw::module_init;
4+
use redismodule::{Context, Command, RedisResult, NextArg};
155
use redismodule::native_types::RedisType;
166

17-
const MODULE_NAME: &str = "alloc";
18-
const MODULE_VERSION: c_int = 1;
19-
20-
#[allow(unused)]
7+
#[derive(Debug)]
218
struct MyType {
229
data: String,
2310
}
2411

25-
static MY_TYPE: RedisType = RedisType::new();
26-
27-
struct AllocSetCommand;
28-
29-
impl CommandOld for AllocSetCommand {
30-
fn name() -> &'static str { "alloc.set" }
31-
32-
fn external_command() -> raw::CommandFunc { AllocSetCommand_Redis }
33-
34-
fn str_flags() -> &'static str { "write" }
35-
36-
// Run the command.
37-
fn run(r: Context, args: &[&str]) -> Result<(), Error> {
38-
if args.len() != 3 {
39-
// FIXME: Use RedisModule_WrongArity instead. Return an ArityError here and
40-
// in the low-level implementation call RM_WrongArity.
41-
return Err(Error::generic(format!(
42-
"Usage: {} <key> <size>", Self::name()
43-
).as_str()));
44-
}
45-
46-
// the first argument is command name (ignore it)
47-
let key = args[1];
48-
let size = parse_i64(args[2])?;
49-
50-
// TODO:
51-
// 1. Open key [OK]
52-
// 2. Allocate data [OK]
53-
// 3. Set the key to the data [OK]
54-
// 4. Activate custom allocator and compare Redis memory usage [OK]
55-
// 5. Handle deallocation of existing value [OK]
56-
57-
let key = r.open_key_writable(key);
58-
let key_type = key.verify_and_get_type(&MY_TYPE)?;
59-
60-
let my = match key_type {
61-
raw::KeyType::Empty => {
62-
// Create a new value
63-
Box::new(
64-
MyType {
65-
data: "A".repeat(size as usize)
66-
}
67-
)
68-
}
69-
_ => {
70-
// There is an existing value, reuse it
71-
let my = key.get_value() as *mut MyType;
72-
73-
if my.is_null() {
74-
r.reply_integer(0)?;
75-
return Ok(());
76-
}
77-
78-
let mut my = unsafe { Box::from_raw(my) };
79-
my.data = "B".repeat(size as usize);
80-
my
81-
}
82-
};
83-
84-
let my = Box::into_raw(my);
85-
86-
key.set_value(&MY_TYPE, my as *mut c_void)?;
87-
r.reply_integer(size)?;
88-
89-
Ok(())
12+
impl Default for MyType {
13+
fn default() -> Self {
14+
MyType { data: Default::default() }
9015
}
9116
}
9217

93-
#[allow(non_snake_case)]
94-
pub extern "C" fn AllocSetCommand_Redis(
95-
ctx: *mut raw::RedisModuleCtx,
96-
argv: *mut *mut raw::RedisModuleString,
97-
argc: c_int,
98-
) -> c_int {
99-
AllocSetCommand::execute(ctx, argv, argc).into()
100-
}
101-
102-
//////////////////////////////////////////////////////
103-
104-
struct AllocGetCommand;
105-
106-
impl CommandOld for AllocGetCommand {
107-
fn name() -> &'static str { "alloc.get" }
18+
static MY_REDIS_TYPE: RedisType = RedisType::new();
10819

109-
fn external_command() -> raw::CommandFunc { AllocGetCommand_Redis }
20+
fn alloc_set(ctx: &Context, args: Vec<String>) -> RedisResult {
21+
let mut args = args.into_iter().skip(1);
22+
let key = args.next_string()?;
23+
let size = args.next_i64()?;
11024

111-
fn str_flags() -> &'static str { "" }
25+
ctx.log_debug(format!("key: {}, size: {}", key, size).as_str());
11226

113-
// Run the command.
114-
fn run(r: Context, args: &[&str]) -> Result<(), Error> {
115-
if args.len() != 2 {
116-
// FIXME: Use RedisModule_WrongArity instead. Return an ArityError here and
117-
// in the low-level implementation call RM_WrongArity.
118-
return Err(Error::generic(format!(
119-
"Usage: {} <key>", Self::name()
120-
).as_str()));
121-
}
27+
let key = ctx.open_key_writable(&key);
12228

123-
// the first argument is command name (ignore it)
124-
let key = args[1];
29+
if key.is_empty() {
30+
let value = MyType {
31+
data: "A".repeat(size as usize)
32+
};
12533

126-
let key = r.open_key(key);
127-
key.verify_and_get_type(&MY_TYPE)?;
128-
let my = key.get_value() as *mut MyType;
34+
ctx.log_debug(format!("key is empty; setting to value: '{:?}'", value).as_str());
12935

130-
if my.is_null() {
131-
r.reply_integer(0)?;
132-
return Ok(());
133-
}
36+
key.set_value(&MY_REDIS_TYPE, value)?;
37+
} else {
38+
ctx.log_debug(format!("key exists; getting value").as_str());
13439

135-
let my = unsafe { &mut *my };
136-
let size = my.data.len();
40+
let value: MyType = key.get_value(&MY_REDIS_TYPE)?;
41+
ctx.log_debug(format!("got value: '{:?}'", value).as_str());
13742

138-
r.reply_array(2)?;
139-
r.reply_integer(size as i64)?;
140-
r.reply_string(my.data.as_str())?;
43+
//value.data = "B".repeat(size as usize);
44+
//ctx.log_debug(format!("new value: '{:?}'", value).as_str());
45+
};
14146

142-
Ok(())
143-
}
47+
Ok(size.into())
14448
}
14549

146-
#[allow(non_snake_case)]
147-
pub extern "C" fn AllocGetCommand_Redis(
148-
ctx: *mut raw::RedisModuleCtx,
149-
argv: *mut *mut raw::RedisModuleString,
150-
argc: c_int,
151-
) -> c_int {
152-
AllocGetCommand::execute(ctx, argv, argc).into()
153-
}
154-
155-
//////////////////////////////////////////////////////
15650

157-
struct AllocDelCommand;
158-
159-
impl CommandOld for AllocDelCommand {
160-
fn name() -> &'static str { "alloc.del" }
161-
162-
fn external_command() -> raw::CommandFunc { AllocDelCommand_Redis }
163-
164-
fn str_flags() -> &'static str { "write" }
165-
166-
// Run the command.
167-
fn run(r: Context, args: &[&str]) -> Result<(), Error> {
168-
if args.len() != 2 {
169-
// FIXME: Use RedisModule_WrongArity instead?
170-
return Err(Error::generic(format!(
171-
"Usage: {} <key>", Self::name()
172-
).as_str()));
173-
}
174-
175-
// the first argument is command name (ignore it)
176-
let _key = args[1];
177-
178-
r.reply_string("OK")?;
179-
180-
Ok(())
181-
}
182-
}
183-
184-
// TODO: Write a macro to generate these glue functions
185-
// TODO: Look at https://github.com/faineance/redismodule which has some macros
51+
/*
52+
fn alloc_get(ctx: &Context, args: Vec<String>) -> RedisResult {
53+
let mut args = args.into_iter().skip(1);
54+
let key = args.next_string()?;
18655
187-
#[allow(non_snake_case)]
188-
pub extern "C" fn AllocDelCommand_Redis(
189-
ctx: *mut raw::RedisModuleCtx,
190-
argv: *mut *mut raw::RedisModuleString,
191-
argc: c_int,
192-
) -> c_int {
193-
AllocDelCommand::execute(ctx, argv, argc).into()
194-
}
56+
let key = ctx.open_key(&key);
19557
196-
fn module_on_load(ctx: *mut raw::RedisModuleCtx) -> Result<(), &'static str> {
197-
module_init(ctx, MODULE_NAME, MODULE_VERSION)?;
58+
key.verify_and_get_type(&MY_REDIS_TYPE)?;
59+
let my = key.get_value() as *mut MyType;
19860
199-
// TODO: Call this from inside module_init
200-
if true {
201-
redismodule::alloc::use_redis_alloc();
61+
if my.is_null() {
62+
r.reply_integer(0)?;
63+
return Ok(());
20264
}
20365
204-
MY_TYPE.create_data_type(ctx, "mytype123")?;
66+
let my = unsafe { &mut *my };
67+
let size = my.data.len();
20568
206-
AllocSetCommand::create(ctx)?;
207-
AllocGetCommand::create(ctx)?;
208-
AllocDelCommand::create(ctx)?;
69+
r.reply_array(2)?;
70+
r.reply_integer(size as i64)?;
71+
r.reply_string(my.data.as_str())?;
20972
21073
Ok(())
21174
}
75+
*/
21276

213-
#[allow(non_snake_case)]
214-
#[no_mangle]
215-
pub extern "C" fn RedisModule_OnLoad(
216-
ctx: *mut raw::RedisModuleCtx,
217-
_argv: *mut *mut raw::RedisModuleString,
218-
_argc: c_int,
219-
) -> c_int {
220-
if let Err(msg) = module_on_load(ctx) {
221-
eprintln!("Error loading module: {}", msg);
222-
return raw::Status::Err.into();
223-
}
77+
//////////////////////////////////////////////////////
22478

225-
raw::Status::Ok.into()
226-
}
79+
const MODULE_NAME: &str = "alloc";
80+
const MODULE_VERSION: c_int = 1;
22781

228-
fn parse_i64(arg: &str) -> Result<i64, Error> {
229-
arg.parse::<i64>()
230-
.map_err(|_| Error::generic(format!("Couldn't parse as integer: {}", arg).as_str()))
231-
}
232-
*/
82+
redis_module!(MODULE_NAME, MODULE_VERSION, [
83+
Command::new("alloc.set", alloc_set, "write"),
84+
]);

examples/hello.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[macro_use]
22
extern crate redismodule;
33

4-
use redismodule::{Context, Command, RedisResult, RedisError};
4+
use redismodule::{Context, Command, RedisResult, RedisError, parse_integer};
55

66
fn hello_mul(_: &Context, args: Vec<String>) -> RedisResult {
77
if args.len() < 2 {
@@ -22,11 +22,6 @@ fn hello_mul(_: &Context, args: Vec<String>) -> RedisResult {
2222
return Ok(response.into());
2323
}
2424

25-
fn parse_integer(arg: String) -> Result<i64, RedisError> {
26-
arg.parse::<i64>()
27-
.map_err(|_| RedisError::String(format!("Couldn't parse as integer: {}", arg)))
28-
}
29-
3025
//////////////////////////////////////////////////////
3126

3227
const MODULE_NAME: &str = "hello";
@@ -79,3 +74,4 @@ mod tests {
7974
}
8075
}
8176
}
77+

0 commit comments

Comments
 (0)