Custom classes in Coherence with OCaml

I have not updated in a little while as I have been busily (re)learning C++ in my already-scarce free time. Seems there is a lot of work around for C++ types, and it’s always good to have options. Anyway, on with the show!

To use a more complex data structure than a primitive type such as a string with the Coherence grid, there are three options:

  1. A native Coherence class. This would be the option if developing from scratch an application that would only ever run on Coherence (e.g. using Coherence’s own String type rather than std::string from the C++ standard library).
  2. Retrofitting an existing class to work with the Managed template. This is probably the easiest method.
  3. Writing a new (de)serializer to work with an existing class. This is the lowest level but highest performance method.

While I am actually developing from scratch here, “systems integration” is my middle name†, so for the purposes of this example I am going to go with option 2 as I consider it to be a more representative scenario of “real work”. The complete code for this example is on GitHub.

The interesting thing about the C++ object definition is that it contains no Coherence-specific code, but it must have:

  • A public or protected zero-parameter constructor
  • A copy constructor
  • A == operator, for equality comparison
  • A << operator (e.g. for use with cout)
  • A hash function, to return a unique identifier

Some of these a class is likely to have anyway. In addition there are two functions, to (de)serialize the objects. These are Coherence-specific, but are “free” so can be implemented independently of the class. I have done some research as to whether it is possible to generate these on-the-fly at runtime as I do with object-types for Oracle AQ and have concluded that it is not; therefore each class corresponding to an OCaml record (or other type) must be coded in C++ at compile time, and this is in addition to the code required to marshal the object to and from OCaml. The reason is of course so that objects in Coherence can be created and transparently accessed by clients in C++, Java and .NET. The good news is that the structure is quite regular and both should be quite amenable to code generation, perhaps from parsing the source code to the original existing class, if available. For this trivial example, storing and retrieving a record of type message in the grid, the C++:OCaml SLOC ratio is ~10:1, but the C++ is very simple‡.

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"

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!"}] in
  let c = coh_getcache "message_cache" in
  List.iter (coh_put_message c) test_msgs;
  print_message (coh_get_message c 1);

Click to enlarge

I had hoped to present a query in this example too (e.g. messages of a certain priority) but looking at the documentation:

After completing any of the above approaches, a data object is ready to be stored within the Coherence cluster. You can perform get and put based operations with your objects. However, to make use of more advanced features of Coherence: such as queries or entry processors; or if you use a key that is not a simple type; or when you use a cache loader and cache store, you must write some Java code.

Emphasis mine. I have all the C++ written, I just need to do that bit, which should be straightforward enough (and again like the C++ can probably be code-generated for the most part). Still, it adds complexity to the solution, which will make the OCaml a harder sell unless what we are actually doing with the cached objects is much better implemented in OCaml than C++, e.g. the sorts of algorithms that functional programming languages are well-suited for, or the kind of prototyping that a very high level language is well suited for, on already-defined objects (so perhaps the Java code backing the C++ code is already done for us!).

Unfortunately however I must conclude that a pure-OCaml interface to Coherence is impossible. However I am confident that my hybrid approach is going to be useful for “real work”, and better than SWIG in this particular case.

UPDATE: Perhaps I can get “close enough” with a PofExtractor.

† Actually it’s Aurelius
‡ Too much to post – see GitHub

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: Logo

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

Twitter picture

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

Facebook photo

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

Connecting to %s