Ruby Java Proxy scanning entire Map

Hello All,

In my project I am exposing a Java Map (a custom java.util.Map instance)
to JRuby code.

From the Ruby code the map seems to have been proxied by an instance of
org.jruby.RubyHash.

I’ve noticed that seems odd to me, if I do the following:

map1[‘key’] = 123
map1[‘key’] = 343
map1[‘key’] = 454

(I.e. overwrite the same key in the map with a different value)

Then the first call results in the method put(key, value) being called
on the Java map (as I would expect)

However, subsequent calls result in entrySet() being called on the Java
map, and all the entries being iterated through in order to find the
matching key, before setting it.

The code that does this is in org.jruby.RubyHash.fastASetCheckString
and org.jruby.java.proxies.MapJavaProxy.op_asetForString.

Am I doing something wrong here? I would expect a put on a well balanced
hash Map to be a fast constant time operation, not a slow scan through
the entire map.

Cheers!

Hello!

On Mon, Aug 22, 2011 at 7:11 AM, Tim F. [email protected] wrote:

map1[‘key’] = 123
key, before setting it.

The code that does this is in org.jruby.RubyHash.fastASetCheckString and
org.jruby.java.proxies.MapJavaProxy.op_asetForString.

Good observation. MapJavaProxy uses RubyHash’s code as much as
possible so that changes to RubyHash will directly affect to wrapped
Map type object. Maybe this policy should be reviewed.

Possibly two bug reports, JRUBY-6006 and JRUBY-5994 are related.

Am I doing something wrong here? I would expect a put on a well balanced
hash Map to be a fast constant time operation, not a slow scan through the
entire map.

No, you aren’t. I’ll look at MapJavaProxy.
If you need better performance right now, perhaps using Java’s method
will solve that.

-Yoko

Yoko,

Thanks for the reply.

Here’s a little more background on the issue: I working on this project
https://github.com/purplefox/node.x It’s an asynchronous application
framework for JVM languages (a bit like node.js but for JVM langs). We
have a central core, which is written in Java, and then we provide a
thin layer in each of the JVM languages we target. One of those
languages is Ruby (JRuby).

One of the services we provide in the core is a shared map
(java.util.Map). We want to expose this in Ruby has a Ruby Hash, and any
updates made to the map from any of the supported languages need to be
visible in any of the others. We don’t really want to expose the Java
methods in Ruby as one of the aims of the project is users in any
particular language should use the idioms the are used to in that
language and we shouldn’t leak Java language or Java API stuff to these
other languages.

On Aug 24, 2011, at 2:26 PM, Tim F. wrote:

Yoko,

Thanks for the reply.

Here’s a little more background on the issue: I working on this project
https://github.com/purplefox/node.x It’s an asynchronous application framework for
JVM languages (a bit like node.js but for JVM langs). We have a central core,
which is written in Java, and then we provide a thin layer in each of the JVM
languages we target. One of those languages is Ruby (JRuby).

One of the services we provide in the core is a shared map (java.util.Map). We
want to expose this in Ruby has a Ruby Hash, and any updates made to the map from
any of the supported languages need to be visible in any of the others. We don’t
really want to expose the Java methods in Ruby as one of the aims of the project
is users in any particular language should use the idioms the are used to in that
language and we shouldn’t leak Java language or Java API stuff to these other
languages.

Sounds like a neat project!

To achieve your goal of adhering to Ruby idioms, you could use a little
delegation to keep that stuff private.

e.g.

class WrappedHash
include Enumerable

def initialize(hash)
@hash = hash
end

def each
@hash.toArray().each { |key, value| yield(key, value) }
end

def
@hash.get(idx)
end

def []=(idx, value)
@hash.put(idx, value)
end

etc

end

So instead of returning a RubyHash, you would return a WrappedHash
instance. You would create all of the usual accessors and hide the
Java-isms inside. So from your end-user’s perspective, they can use all
of their same idioms and everything will “just work.”

This would only be temporary until your original performance complaint
is repaired.

cr

FWIW, I have made modifications (post 1.6.4) that make the
Hashification of Map a bit more direct. You should see the behavior
you expect, with [] always doing a get, []= always doing a put, and so
on. Performance should also be quite a bit better for most uses.

See http://jira.codehaus.org/browse/JRUBY-5994 for information on the
fixes.

  • Charlie

Within the next month, I hope :slight_smile:

Great, thanks :slight_smile:

Any idea when 1.6.5 will be out?