Hello! I’m trying to create a Redis module in Kot...
# kotlin-native
m
Hello! I’m trying to create a Redis module in Kotlin/Native. The module will provide a stack data type:
Copy code
class Node(prev: Node?, value: Char)
class Stack(tail: Node?)
Redis provides a specific API for memory allocation:
void *RedisModule_Alloc(size_t bytes)
. They say it should be preferred over
malloc
because “memory allocated with this function is reported in Redis INFO memory, used for keys eviction according to maxmemory settings and in general is taken into account as memory allocated by Redis”. So, I want to use this API to allocate memory for my nodes. My plan was to reinterpret that pointers to my types later. The problem is that I cannot find a way to know the size needed by my claasses, like
sizeOf<Node>
. How do I know it?
a
Hello! Can you describe a little bit, what are you trying to do here? If I understood you correctly, you want to implement some class in K/N and then use it as a C structure. I think it won’t work this way, as all Kotlin/Native class allocations are operated by its garbage collector.
m
Hello, @Artyom Degtyarev [JB]! Thank you for the response, and sorry for the delayed answer. I want to implement a structure to check the validity of a brackets expression in Redis. You know, a special version of a stack, based on a linked list. I've actually had some progress since the question was asked, here is the code: https://gitlab.com/madhead-playgrounds/redis/-/blob/wip/kn/src/linuxX64Main/kotlin/bracketsType.kt#L39-72 It seems to be working, but now I am not sure about other aspects of the code. Particularly: 1. Is it correct to use a
StableRef
to pass
void *
to the C code here, on lines 113, 117, 155. I guess, Redis just stores it somewhere in the memory for some time. My concern is that the object tree (the linked list) may become obsolete, invalid, and I could get a segfault. 2. I'm using
memScoped { "string".cstr.ptr }
every time I need to pass a
const char *
to the C code (
RedisModule_ReplyWithLongLong
). Is it ok? The generated Kotlin interfaces expects a `CPointer``, not a
CValues
n
Isn't the GC in Kotlin Native only for handling cyclic references? Is ARC no longer the primary memory model used by Kotlin Native?
🤷‍♂️ 1
a
@napperley I meant that all classes from the resulting library, it’s hard to treat them like ordinary C structures. Exactly because of reference counting, but in a more general way, because of K/N runtime, whos manage memory on its own. I used a bit wrong term here.
@madhead About your questions above - 1. this StableRef use seems incorrect in a very dangerous way, and that’s why. As you can find in the documentation,
Any StableRef should be manually disposed
. If you do not dispose
StableRefs
, it will result in memory leaks, as reference counting would be working incorrectly for them. In fact, that’s what I was talking originally - Kotlin/Native classes are hard to get cut away from its runtime, it was laid in the compiler design. 2. The problem here is that all guarantees of your const char presence under this pointer will be gone as soon as the
memScoped
block ends. I’m still unfamiliar with all this Redis stuff, so I cannot say if this is okay here, but presumably, this is an error-prone approach. Maybe it would be better to allocate all these strings in some
Arena
class instance, with clearing it by your demand.
m
Thank you, Artyom! 1. Redis has a free function for the data structures, it’s just not yet implemented by me:
bracketsFree
in my code. It will be called when Redis is about to dispose the key’s value (when it’s deleted or evicted due to low memory). Am I safe if i call a
dispose
here? 2. I’ll try to check if Redis copies that strings, it’s unclear from the docs. I guess that if if does a memcopy here — I am safe, if it’s not — I should probably allocate that string in
nativeHeap
a
Nice! That seems like a very good place to dispose your StableRefs. About strings you also got it right. The only important thing here is that
nativeHeap
, documentation example of it’s use is kinda incorrect, see here(https://kotlinlang.slack.com/archives/C3SGXARS6/p1556275050056600?thread_ts=1556274437.055700&amp;cid=C3SGXARS6).
m
Cool, I’ll use this one-liner:
"ss".cstr.place(nativeHeap.allocArray(s.length * 4))
Thanks a lot!