redis_module/
alloc.rs

1use std::alloc::{GlobalAlloc, Layout};
2
3use crate::raw;
4
5/// Panics with a message without using an allocator.
6/// Useful when using the allocator should be avoided or it is
7/// inaccessible. The default [std::panic] performs allocations and so
8/// will cause a double panic without a meaningful message if the
9/// allocator can't be used. This function makes sure we can panic with
10/// a reasonable message even without the allocator working.
11fn allocation_free_panic(message: &'static str) -> ! {
12    use std::os::unix::io::AsRawFd;
13
14    let _ = nix::unistd::write(std::io::stderr().as_raw_fd(), message.as_bytes());
15
16    std::process::abort();
17}
18
19const REDIS_ALLOCATOR_NOT_AVAILABLE_MESSAGE: &str =
20    "Critical error: the Redis Allocator isn't available.\n";
21
22/// Defines the Redis allocator. This allocator delegates the allocation
23/// and deallocation tasks to the Redis server when available, otherwise
24/// it panics.
25#[derive(Copy, Clone)]
26pub struct RedisAlloc;
27
28unsafe impl GlobalAlloc for RedisAlloc {
29    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
30        /*
31         * To make sure the memory allocation by Redis is aligned to the according to the layout,
32         * we need to align the size of the allocation to the layout.
33         *
34         * "Memory is conceptually broken into equal-sized chunks,
35         * where the chunk size is a power of two that is greater than the page size.
36         * Chunks are always aligned to multiples of the chunk size.
37         * This alignment makes it possible to find metadata for user objects very quickly."
38         *
39         * From: https://linux.die.net/man/3/jemalloc
40         */
41        let size = (layout.size() + layout.align() - 1) & (!(layout.align() - 1));
42
43        match raw::RedisModule_Alloc {
44            Some(alloc) => alloc(size).cast(),
45            None => allocation_free_panic(REDIS_ALLOCATOR_NOT_AVAILABLE_MESSAGE),
46        }
47    }
48
49    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
50        match raw::RedisModule_Free {
51            Some(f) => f(ptr.cast()),
52            None => allocation_free_panic(REDIS_ALLOCATOR_NOT_AVAILABLE_MESSAGE),
53        };
54    }
55}