In this post I will demonstrate triggering the execution of OCaml code by events within the Coherence grid. The full code is on GitHub, but at the OCaml level it is designed to be very simple†, using the callback mechanism. This is listener.ml
:
open Cohml open Callback open Unix let cbf_coh_insert k v = print_endline ("Inserted key=" ^ k ^ " value=" ^ v) let _ = register "cbf_coh_insert" cbf_coh_insert let cbf_coh_update k ov nv = print_endline ("Updated key=" ^ k ^ " old value=" ^ ov ^ " new value=" ^ nv) let _ = register "cbf_coh_update" cbf_coh_update let cbf_coh_delete k = print_endline ("Deleted key=" ^ k) let _ = register "cbf_coh_delete" cbf_coh_delete let () = print_endline "Listening..."; let c = coh_getcache "test_cache" in coh_listen c ; sleep 1000
The new library function is coh_listen
on line 17. It sleeps after registering for callbacks, but could do some additional processing if thread-safe. The registered names correspond to those in the lower-level C++, an excerpt from cohml.c
:
void CohmlMapListener::entryInserted(MapEvent::View vEvent) { // TODO: stash these function pointers caml_callback2(*caml_named_value("cbf_coh_insert"), caml_copy_string(cast<String::View>(vEvent->getKey())->getCString()), caml_copy_string(cast<String::View>(vEvent->getNewValue())->getCString())); } // call the OCaml function cbf_coh_update with the key, the previous value and the new value void CohmlMapListener::entryUpdated(MapEvent::View vEvent) { caml_callback3(*caml_named_value("cbf_coh_update"), caml_copy_string(cast<String::View>(vEvent->getKey())->getCString()), caml_copy_string(cast<String::View>(vEvent->getOldValue())->getCString()), caml_copy_string(cast<String::View>(vEvent->getNewValue())->getCString())); } // call the OCaml function cb_coh_delete with the key just removed from the cache void CohmlMapListener::entryDeleted(MapEvent::View vEvent) { caml_callback(*caml_named_value("cbf_coh_delete"), caml_copy_string(cast<String::View>(vEvent->getKey())->getCString())); }
Now if we run up the listener
process and manipulate the cache from cohmlsh
in another window:
We can clearly see our callback functions being executed:
This is still trivial but it is a definite step in the direction of doing “real work” with this‡. The next challenge will be to do all this with a more sophisticated data structure than just a string. I would like to keep everything within OCaml (as I have managed to do in OCI*ML) but it is looking increasingly like each one will require some custom C++ as reverse-engineering POF is well beyond me! I will also need a way to pass the callback names into Coherence – a
MapListener
is created not with new
but with a ::create()
factory method, so I never actually “have” it to set properties on. This is so I can listen to more than one cache at a time.
Towards that end I have have bought a copy of Bruce Eckel’s Thinking in C++. Reading it is giving me a strange sense of déjà vu…
† This is possibly because we are still only using strings!
‡Get something off the grid, process it in OCaml and store it in the database, for example, or vice-versa
I C++ advatageous or can standard ANSI C be used
The Coherence API is C++ and uses features not present in C (e.g. smart pointers). I am using a thin C layer to bridge between OCaml and C++.
ahh, c++ smart pointers looks like a move forward from c pointers e.g. automatic bounds checking and garbage collection instead free when finished with the memory.
takes all the fun out of c 😉
I’ve been taking a look a @ http://www.linux-nantes.org/~fmonnier/OCaml/ocaml-wrapping-c.php#ref_quick_start as a primer on OCaml
It’s a good article, but probably the best place to start is here or here.
Enjoy you blog – look forward to some more posts.
Thanks 🙂