-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot put 'Term' inside 'ResourceArc', or: Support for storing references to Erlang datatypes in Rustler structs? #333
Comments
We can't really do this, we wrap the C NIF API, and this is not supported functionality there. One possibility to accomplish what you are trying to do could be to allocate an owned environment, and then use that for storing terms outside of the process heap. This is a really interesting idea actually, and we should probably look into implementing it. It would require testing to figure out any potential caveats to this approach in regards to memory usage or performance. |
Thank you for you reply! I had a go making a simple implementation of a managed mutable box type using an owned environment: use rustler::env::OwnedEnv;
use rustler::env::SavedTerm;
// Put this in a ResourceArc:
pub struct MutableTermBox
{
inner: std::sync::Mutex<MutableTermBoxContents>,
}
struct MutableTermBoxContents
{
owned_env: OwnedEnv,
saved_term: SavedTerm
}
impl MutableTermBox {
pub fn new(term: Term) -> Self {
Self{inner: std::sync::Mutex::new(MutableTermBoxContents::new(term))}
}
pub fn get<'a>(&self, env: Env<'a>) -> Term<'a> {
let inner = self.inner.lock().unwrap();
// Copy over term from owned environment to the target environment
inner.owned_env.run(|inner_env| {
let term = inner.saved_term.load(inner_env);
term.in_env(env)
})
}
pub fn set(&self, term: Term) -> Atom {
let mut term_ptr = self.inner.lock().unwrap();
term_ptr.owned_env.clear();
term_ptr.saved_term = term_ptr.owned_env.save(term);
atoms::ok()
}
}
impl MutableTermBoxContents {
fn new(term: Term) -> Self {
let owned_env = OwnedEnv::new();
let saved_term = owned_env.save(term);
Self{owned_env: owned_env, saved_term: saved_term}
}
} Since I'm new to Rustler there probably are some ways to improve this further. |
As for memory usage/efficiency: I have not done any profiling so far (nor do I know what a good approach would be to profiling this kind of code), but I did have a look at the internals of the BEAM's erl_nif.c implementation.
|
I have another idea: If e.g. an ETS handle is created and then moved to inside an OwnedEnv, we can read/write to this ETS data from anywhere without incurring the copying overhead that we'd have from moving terms into and out of the owned environment directly. So this might allocating and de-allocating an owned environment slightly slower, but will probably significantly increase the read/write speed from/to it. This is probably worthwhile. |
I'm pretty sure reading and writing from ETS also performs a copy of the term.
…On Wed, Oct 21, 2020, at 00:03, Qqwy wrote:
I have another idea: If e.g. an ETS handle is created and then moved to inside an OwnedEnv, we can read/write to this ETS data from anywhere without incurring the copying overhead that we'd have from moving terms into and out of the owned environment directly.
So this might allocating and de-allocating an owned environment slightly slower, but will probably significantly increase the read/write speed from/to it. This is probably worthwhile.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#333 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGN7UTV3YXZCRHCF5SHTPTSLYCL7ANCNFSM4SAPCBXQ>.
|
@hansihe Yes, unfortunately it does. I think the 'OwnedEnv' is the best we can do right now. It would be great if a hook would be added to EDIT: Of course, it might be difficult to do so without interfering with Erlang's garbage collector which might invalidate pointers. I think this would be the final piece of the puzzle to allow us to use native containers (arrays, vectors, queues, and the likes) which could be very useful in certain circumstances. |
For some use cases (c.f. christian-public/Idris2-Erlang#4) it would be nice to store references to Erlang datastructures inside a Rust structure.
Converting (serializing) the data to Rust types before storage is slow and breaks for certain types like references which might be garbage-collected and then later when deserializing the data they might be no longer valid. A prime example is the Erlang 'ref' type (such as used by
:atomics
,:counter
or NIF modules).ResourceArc might store a pointer to an arbitrary Erlang term inside (as long as the ResourceArc as a whole is constructed/passed back to the same Env the term came from), but currently this is not possible because
Term
itself does not have aResourceTypeProvider
implementation.Either adding a
ResourceTypeProvider
implementation forType
or adding a separate class called e.g.TermArc
whose implementation would be similar toResourceArc
but simpler since no type-conversions would need to take place would be possibilities.The text was updated successfully, but these errors were encountered: