Queries in Coherence with OCaml

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.

About Gaius

Jus' a good ol' boy, never meanin' no harm
This entry was posted in C++, Coherence, COHML, Ocaml, Operation Foothold. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s