> we could cache the method id - if we don't mind a static global var to stash it

Let's not do that, though I am concerned about the overhead of doing two function lookups per callback.

> Java does all transfers using 'raw' mode and packs/unpacks within Java

That is done to save crossing the API boundary lots of times for a single API call.

> Rather than incurring the cost of unpacking both key and value up front, instead resetResults() invalidates the unpackers, and on the first call to op.getKey(), the key unpacking is done, and on first call to op.getValue(), the value unpacking is done. 

That sounds reasonable as long as the memory (which belongs to the C cursor) is still valid when getKey and getValue are called. I'm not convinced that the memory is guaranteed to be available after the callback has returned, since the async code could (presumably) pick the thread up from the pool and use it to make another callback.

@michaelcahill This one is moving past my knowledge of the async API, could you take a look when you have a chance?