Igniters,
Lots of our features rely on callbacks from Ignite to user code. This is essential for task execution, cache invokes, cache store, continuous queries, messaging, etc.. Ideally from user perspective target class should look somewhat like this: class MyListener : public IListener<MyKey*, MyVal*> { public: bool Invoke(MyKey*, MyType*); } And Java -> C++ linking code will be something like this: jboolean JniListenerCallback(JNIEnv *env, jclass cls, jlong ptr, _others_) { int callbackType = type(_others_); switch (callbackType) { ... case 6: MyKey* key = unmarshal<MyKey*>(_others_); MyVal* val = unmarshal<MyVal*>(_others_); return reinterpret_cast<MyListener>(ptr).Invoke(_others_); case 7: MyOtherKey* key = unmarshal<MyOtherKey*>(_others_); MyOtherVal* val = unmarshal<MyOtherVal*>(_others_); return reinterpret_cast<MyOtherListener>(ptr).Invoke(_other_); ... } } Looks like we can implement it as follows: 1) Ask user to provide function pointer (or lib_name + func_name for standalone node) for specific callback type to configuration. 2) This function, in turn, must be implemented by user with our macros, somehow like this: IGNITE_LISTENER_CALLBACK(MyListenerCallback) ( IGNITE_ADD_LISTENER_CALLBACK(6, MyListener, MyKey*, MyVal*) IGNITE_ADD_LISTENER_CALLBACK(7, MyOtherListener, MyOtherKey*, MyOtherVal*) ) Looks like it should do the trick and enable C++ code execution through callbacks. Any comments or ideas? May be we can employ visitor/double-dispatch technique somehow here? Or something completely different? Vladimir. |
Ugh, JNI.
Aren't we worried about portability here? IMO it's not easy to build robust applications with JNI but not sure that's a concern for us given that this is all in user space. .. On 4 Jun 2015 19:16, "Vladimir Ozerov" <[hidden email]> wrote: > Igniters, > > Lots of our features rely on callbacks from Ignite to user code. This is > essential for task execution, cache invokes, cache store, continuous > queries, messaging, etc.. > > Ideally from user perspective target class should look somewhat like this: > class MyListener : public IListener<MyKey*, MyVal*> { > public: > bool Invoke(MyKey*, MyType*); > } > > And Java -> C++ linking code will be something like this: > jboolean JniListenerCallback(JNIEnv *env, jclass cls, jlong ptr, _others_) > { > int callbackType = type(_others_); > > switch (callbackType) { > ... > case 6: > MyKey* key = unmarshal<MyKey*>(_others_); > MyVal* val = unmarshal<MyVal*>(_others_); > return reinterpret_cast<MyListener>(ptr).Invoke(_others_); > case 7: > MyOtherKey* key = unmarshal<MyOtherKey*>(_others_); > MyOtherVal* val = unmarshal<MyOtherVal*>(_others_); > return reinterpret_cast<MyOtherListener>(ptr).Invoke(_other_); > ... > } > } > > Looks like we can implement it as follows: > 1) Ask user to provide function pointer (or lib_name + func_name for > standalone node) for specific callback type to configuration. > 2) This function, in turn, must be implemented by user with our macros, > somehow like this: > IGNITE_LISTENER_CALLBACK(MyListenerCallback) ( > IGNITE_ADD_LISTENER_CALLBACK(6, MyListener, MyKey*, MyVal*) > > IGNITE_ADD_LISTENER_CALLBACK(7, MyOtherListener, MyOtherKey*, > MyOtherVal*) > ) > > Looks like it should do the trick and enable C++ code execution through > callbacks. > > Any comments or ideas? May be we can employ visitor/double-dispatch > technique somehow here? Or something completely different? > > Vladimir. > |
I do not see any new portability issues JNI can add. I.e. user on Windows
machine put an object to cache using JNI and Ignite libs for Windows. We marshal that object to portable form. Then Linux user is notified about put using JNI and Ignite libs for Linux. As per compatibility between different Java versions, there should not be any problems given that Java maintains binary compatibility between versions and we are not going to statically link jvm.so/jvm.dll. On Thu, Jun 4, 2015 at 4:52 PM, Atri Sharma <[hidden email]> wrote: > Ugh, JNI. > > Aren't we worried about portability here? IMO it's not easy to build robust > applications with JNI but not sure that's a concern for us given that this > is all in user space. .. > On 4 Jun 2015 19:16, "Vladimir Ozerov" <[hidden email]> wrote: > > > Igniters, > > > > Lots of our features rely on callbacks from Ignite to user code. This is > > essential for task execution, cache invokes, cache store, continuous > > queries, messaging, etc.. > > > > Ideally from user perspective target class should look somewhat like > this: > > class MyListener : public IListener<MyKey*, MyVal*> { > > public: > > bool Invoke(MyKey*, MyType*); > > } > > > > And Java -> C++ linking code will be something like this: > > jboolean JniListenerCallback(JNIEnv *env, jclass cls, jlong ptr, > _others_) > > { > > int callbackType = type(_others_); > > > > switch (callbackType) { > > ... > > case 6: > > MyKey* key = unmarshal<MyKey*>(_others_); > > MyVal* val = unmarshal<MyVal*>(_others_); > > return reinterpret_cast<MyListener>(ptr).Invoke(_others_); > > case 7: > > MyOtherKey* key = unmarshal<MyOtherKey*>(_others_); > > MyOtherVal* val = unmarshal<MyOtherVal*>(_others_); > > return reinterpret_cast<MyOtherListener>(ptr).Invoke(_other_); > > ... > > } > > } > > > > Looks like we can implement it as follows: > > 1) Ask user to provide function pointer (or lib_name + func_name for > > standalone node) for specific callback type to configuration. > > 2) This function, in turn, must be implemented by user with our macros, > > somehow like this: > > IGNITE_LISTENER_CALLBACK(MyListenerCallback) ( > > IGNITE_ADD_LISTENER_CALLBACK(6, MyListener, MyKey*, MyVal*) > > > > IGNITE_ADD_LISTENER_CALLBACK(7, MyOtherListener, MyOtherKey*, > > MyOtherVal*) > > ) > > > > Looks like it should do the trick and enable C++ code execution through > > callbacks. > > > > Any comments or ideas? May be we can employ visitor/double-dispatch > > technique somehow here? Or something completely different? > > > > Vladimir. > > > |
In reply to this post by Vladimir Ozerov
On 04.06.2015 15:45, Vladimir Ozerov wrote:
> Igniters, > > Lots of our features rely on callbacks from Ignite to user code. This is > essential for task execution, cache invokes, cache store, continuous > queries, messaging, etc.. > > Ideally from user perspective target class should look somewhat like this: > class MyListener : public IListener<MyKey*, MyVal*> { > public: > bool Invoke(MyKey*, MyType*); > } Please please please do not use raw pointers in the public API. This is a memory management nightmare waiting to happen. Either use const references or shared pointers. std::auto_ptr_ref is an option, but not a very good one. -- Brane |
Something like a smart pointer might be useful here.
I thing that I also feel that the memory handling of the C++ objects might be the biggest issue here. What I think can happen is having Java objects *own* C++ objects and clean up in finalize() methods. Only a small idea though... On Thu, Jun 4, 2015 at 8:23 PM, Branko Čibej <[hidden email]> wrote: > On 04.06.2015 15:45, Vladimir Ozerov wrote: > > Igniters, > > > > Lots of our features rely on callbacks from Ignite to user code. This is > > essential for task execution, cache invokes, cache store, continuous > > queries, messaging, etc.. > > > > Ideally from user perspective target class should look somewhat like > this: > > class MyListener : public IListener<MyKey*, MyVal*> { > > public: > > bool Invoke(MyKey*, MyType*); > > } > > Please please please do not use raw pointers in the public API. This is > a memory management nightmare waiting to happen. Either use const > references or shared pointers. std::auto_ptr_ref is an option, but not a > very good one. > > -- Brane > > -- Regards, Atri *l'apprenant* |
On 04.06.2015 17:10, Atri Sharma wrote:
> Something like a smart pointer might be useful here. > > I thing that I also feel that the memory handling of the C++ objects might > be the biggest issue here. What I think can happen is having Java objects > *own* C++ objects and clean up in finalize() methods. Only a small idea > though... From my experience, finalize() happens far too late to be useful. There's a very fundamental impedance mismatch between Java and C++: C++ has destructors, Java doesn't; and finalize() is not a good replacement for a destructor because it doesn't know squat about scope. For callbacks, it's probably best to just transfer ownership of objects from Java to C++: that would imply creating the object in the JNI layer, then sending an std::auto_ptr (or std::unique_ptr in C++11) to the callback handler. Once it owns the object the C++ app can do whatever it wants with it. If that's not possible, the second option is to use proxy objects instead of real value objects in the callbacks. Proxy objects are C++ objects that contain a global reference to a Java object and whose native methods are just wrappers to JNIEnv::Call*Method. The constructor and assignment operators would always create new global references and the destructor would release the global reference and you'd have almost Java-like garbage collection semantics. -- Brane > On Thu, Jun 4, 2015 at 8:23 PM, Branko Čibej <[hidden email]> wrote: > >> On 04.06.2015 15:45, Vladimir Ozerov wrote: >>> Igniters, >>> >>> Lots of our features rely on callbacks from Ignite to user code. This is >>> essential for task execution, cache invokes, cache store, continuous >>> queries, messaging, etc.. >>> >>> Ideally from user perspective target class should look somewhat like >> this: >>> class MyListener : public IListener<MyKey*, MyVal*> { >>> public: >>> bool Invoke(MyKey*, MyType*); >>> } >> Please please please do not use raw pointers in the public API. This is >> a memory management nightmare waiting to happen. Either use const >> references or shared pointers. std::auto_ptr_ref is an option, but not a >> very good one. >> >> -- Brane >> >> > |
I like proxy objects although I am wondering if that makes copy by value
any more expensive (I am not sure about deep copying of non native objects) On 4 Jun 2015 22:01, "Branko Čibej" <[hidden email]> wrote: > On 04.06.2015 17:10, Atri Sharma wrote: > > Something like a smart pointer might be useful here. > > > > I thing that I also feel that the memory handling of the C++ objects > might > > be the biggest issue here. What I think can happen is having Java objects > > *own* C++ objects and clean up in finalize() methods. Only a small idea > > though... > > From my experience, finalize() happens far too late to be useful. > > There's a very fundamental impedance mismatch between Java and C++: C++ > has destructors, Java doesn't; and finalize() is not a good replacement > for a destructor because it doesn't know squat about scope. > > For callbacks, it's probably best to just transfer ownership of objects > from Java to C++: that would imply creating the object in the JNI layer, > then sending an std::auto_ptr (or std::unique_ptr in C++11) to the > callback handler. Once it owns the object the C++ app can do whatever it > wants with it. > > If that's not possible, the second option is to use proxy objects > instead of real value objects in the callbacks. Proxy objects are C++ > objects that contain a global reference to a Java object and whose > native methods are just wrappers to JNIEnv::Call*Method. The constructor > and assignment operators would always create new global references and > the destructor would release the global reference and you'd have almost > Java-like garbage collection semantics. > > -- Brane > > > On Thu, Jun 4, 2015 at 8:23 PM, Branko Čibej <[hidden email]> wrote: > > > >> On 04.06.2015 15:45, Vladimir Ozerov wrote: > >>> Igniters, > >>> > >>> Lots of our features rely on callbacks from Ignite to user code. This > is > >>> essential for task execution, cache invokes, cache store, continuous > >>> queries, messaging, etc.. > >>> > >>> Ideally from user perspective target class should look somewhat like > >> this: > >>> class MyListener : public IListener<MyKey*, MyVal*> { > >>> public: > >>> bool Invoke(MyKey*, MyType*); > >>> } > >> Please please please do not use raw pointers in the public API. This is > >> a memory management nightmare waiting to happen. Either use const > >> references or shared pointers. std::auto_ptr_ref is an option, but not a > >> very good one. > >> > >> -- Brane > >> > >> > > > > |
On 04.06.2015 18:42, Atri Sharma wrote:
> I like proxy objects although I am wondering if that makes copy by value > any more expensive (I am not sure about deep copying of non native objects) Note that the only data a proxy object contains is the Java reference -- a pointer by the current JNI definition. What makes copying more expensive is the requirement to maintain a Java global reference in each copy. For this, you can either use JNI's NewGlobalRef/DeleteGlobalRef, or some kind of native reference counting in C++ -- effectively a shared pointer to a (wrapped) Java global reference. I have no ides what's faster, but I suspect that the letting JNI take care of reference handling is the better option. -- Brane > On 4 Jun 2015 22:01, "Branko Čibej" <[hidden email]> wrote: > >> On 04.06.2015 17:10, Atri Sharma wrote: >>> Something like a smart pointer might be useful here. >>> >>> I thing that I also feel that the memory handling of the C++ objects >> might >>> be the biggest issue here. What I think can happen is having Java objects >>> *own* C++ objects and clean up in finalize() methods. Only a small idea >>> though... >> From my experience, finalize() happens far too late to be useful. >> >> There's a very fundamental impedance mismatch between Java and C++: C++ >> has destructors, Java doesn't; and finalize() is not a good replacement >> for a destructor because it doesn't know squat about scope. >> >> For callbacks, it's probably best to just transfer ownership of objects >> from Java to C++: that would imply creating the object in the JNI layer, >> then sending an std::auto_ptr (or std::unique_ptr in C++11) to the >> callback handler. Once it owns the object the C++ app can do whatever it >> wants with it. >> >> If that's not possible, the second option is to use proxy objects >> instead of real value objects in the callbacks. Proxy objects are C++ >> objects that contain a global reference to a Java object and whose >> native methods are just wrappers to JNIEnv::Call*Method. The constructor >> and assignment operators would always create new global references and >> the destructor would release the global reference and you'd have almost >> Java-like garbage collection semantics. >> >> -- Brane >> >>> On Thu, Jun 4, 2015 at 8:23 PM, Branko Čibej <[hidden email]> wrote: >>> >>>> On 04.06.2015 15:45, Vladimir Ozerov wrote: >>>>> Igniters, >>>>> >>>>> Lots of our features rely on callbacks from Ignite to user code. This >> is >>>>> essential for task execution, cache invokes, cache store, continuous >>>>> queries, messaging, etc.. >>>>> >>>>> Ideally from user perspective target class should look somewhat like >>>> this: >>>>> class MyListener : public IListener<MyKey*, MyVal*> { >>>>> public: >>>>> bool Invoke(MyKey*, MyType*); >>>>> } >>>> Please please please do not use raw pointers in the public API. This is >>>> a memory management nightmare waiting to happen. Either use const >>>> references or shared pointers. std::auto_ptr_ref is an option, but not a >>>> very good one. >>>> >>>> -- Brane >>>> >>>> >> |
In reply to this post by Vladimir Ozerov
Vova,
Is this change backward compatible? D. On Thu, Jun 4, 2015 at 4:45 PM, Vladimir Ozerov <[hidden email]> wrote: > Igniters, > > Lots of our features rely on callbacks from Ignite to user code. This is > essential for task execution, cache invokes, cache store, continuous > queries, messaging, etc.. > > Ideally from user perspective target class should look somewhat like this: > class MyListener : public IListener<MyKey*, MyVal*> { > public: > bool Invoke(MyKey*, MyType*); > } > > And Java -> C++ linking code will be something like this: > jboolean JniListenerCallback(JNIEnv *env, jclass cls, jlong ptr, _others_) > { > int callbackType = type(_others_); > > switch (callbackType) { > ... > case 6: > MyKey* key = unmarshal<MyKey*>(_others_); > MyVal* val = unmarshal<MyVal*>(_others_); > return reinterpret_cast<MyListener>(ptr).Invoke(_others_); > case 7: > MyOtherKey* key = unmarshal<MyOtherKey*>(_others_); > MyOtherVal* val = unmarshal<MyOtherVal*>(_others_); > return reinterpret_cast<MyOtherListener>(ptr).Invoke(_other_); > ... > } > } > > Looks like we can implement it as follows: > 1) Ask user to provide function pointer (or lib_name + func_name for > standalone node) for specific callback type to configuration. > 2) This function, in turn, must be implemented by user with our macros, > somehow like this: > IGNITE_LISTENER_CALLBACK(MyListenerCallback) ( > IGNITE_ADD_LISTENER_CALLBACK(6, MyListener, MyKey*, MyVal*) > > IGNITE_ADD_LISTENER_CALLBACK(7, MyOtherListener, MyOtherKey*, > MyOtherVal*) > ) > > Looks like it should do the trick and enable C++ code execution through > callbacks. > > Any comments or ideas? May be we can employ visitor/double-dispatch > technique somehow here? Or something completely different? > > Vladimir. > |
In reply to this post by Branko Čibej
On 04.06.2015 18:49, Branko Čibej wrote:
> On 04.06.2015 18:42, Atri Sharma wrote: >> I like proxy objects although I am wondering if that makes copy by value >> any more expensive (I am not sure about deep copying of non native objects) > Note that the only data a proxy object contains is the Java reference -- > a pointer by the current JNI definition. What makes copying more > expensive is the requirement to maintain a Java global reference in each > copy. For this, you can either use JNI's NewGlobalRef/DeleteGlobalRef, > or some kind of native reference counting in C++ -- effectively a shared > pointer to a (wrapped) Java global reference. I have no ides what's > faster, but I suspect that the letting JNI take care of reference > handling is the better option. Something like the attached prototype. -- Brane |
Free forum by Nabble | Edit this page |