Well, it looks like I posted the last entry too soon, as I can get close to what I want to do with the PofExtractor available from Coherence 3.5 onwards, without needing to write any Java (ugh!). It is a 1-line change to the C++, and a couple of OCaml lines to access the new functionality. The new example puts two message
records in the cache, then retrieves the high priority one:
open Cohml open Printf open Log_message type message = {msg_id : int; msg_priority : int; msg_subject : string; msg_body : string} external coh_put_message: coh_ptr -> message -> unit = "caml_put_message" external coh_get_message: coh_ptr -> int -> message = "caml_get_message" external coh_pri_message: coh_ptr -> int -> message list = "caml_query_message_pri" let print_message m = log_message (sprintf "id=%d, priority=%d, subject='%s', body='%s'\n" m.msg_id m.msg_priority m.msg_subject m.msg_body) let () = let test_msgs = [{msg_id = 1; msg_priority=3; msg_subject="test"; msg_body="hello, world!"}; {msg_id = 2; msg_priority=1; msg_subject="urgent!"; msg_body="High priority message"}] in let c = coh_getcache "message_cache" in List.iter (coh_put_message c) test_msgs; print_message (List.hd (coh_pri_message c 2));
The new C++ method, in cohml.c
:
vector<Message*>* Cohml::query_message_pri(int k) { vector<Message*>* msgv = new vector<Message*>; // field 1 is the priority of type int PofExtractor::Handle hExtractor = PofExtractor::create(typeid(int32_t), 1); Filter::View vFilter = LessEqualsFilter::create(hExtractor, Integer32::create(k)); for (Iterator::Handle hIter = hCache->entrySet(vFilter)->iterator(); hIter->hasNext() š { Map::Entry::Handle hEntry = cast<Map::Entry::Handle>(hIter->next()); Integer32::View vKey = cast<Integer32::View>(hEntry->getKey()); Managed<Message>::View vMessage = cast<Managed<Message>::View>(hCache->get(vKey)); #ifdef DEBUG msg << __func__ << ": retrieved message: " << vMessage; debug(msg.str().c_str()); #endif Message* m = new Message(vMessage->getId(), vMessage->getPriority(), vMessage->getSubject(), vMessage->getBody()); msgv->push_back(m); } return msgv; }
Replacing:
ValueExtractor::Handle hExtractor = ReflectionExtractor::create("getPriority");
On the way I encountered a bug that causes a segmentation fault in List.iter
:
Program received signal SIGSEGV, Segmentation fault. 0x08085570 in caml_interprete () (gdb) bt #0 0x08085570 in caml_interprete () #1 0x08074992 in caml_main () #2 0x080846a8 in main () (gdb)
Thanks to the time-reversing capabilities of Ocamldebug I can peer into the interpreter:
Lost connection with process 27541 (active process) between time 1970 and time 1971 Tue Aug 16 17:13:02 2011: id=2, priority=1, subject='urgent!', body='High priority message' Time : 1970 - pc : 14392 - module List 69 | a::l -> f a<|a|>; iter f l (ocd)
This is why I am using List.hd
there on line 18 instead of:
List.iter print_message (coh_pri_message c 2);
UPDATE 17th August: This was a bug in my C++ code, I was constructing an Array
but treating it as a List
in OCaml. D’oh! Fixed now and pushed to GitHub.
Anyway, the moral of the story is, don’t trust the documentation! Which was even for a later version than this feature was introduced in.
Also, writing C++ really makes you appreciate type inference. Most of the code above is type annotation and coercion. But like I say, it should be possible to just generate much of it.