Error on connecting to RonDB using ClusterJ approach

We have a functioning RonDB cluster setup and read and write to it using MySQL interface.
We are currently exploring connecting to RonDB cluster using ClusterJ interface as suggested in this thread.
We are referring to startup sample code available here.

    public static void main (String[] args)  {
        Properties props = new Properties();
        props.put("com.mysql.clusterj.connectstring", "x.x.x.x:1186");
        props.put("com.mysql.clusterj.database", "clusterdb");
        props.put("com.mysql.clusterj.connect.retries", "4");
        props.put("com.mysql.clusterj.connect.delay", "5");
        props.put("com.mysql.clusterj.connect.verbose", "1");
        props.put("com.mysql.clusterj.connect.timeout.before", "30");
        props.put("com.mysql.clusterj.connect.timeout.after", "20");
        props.put("com.mysql.clusterj.max.transactions", "1024");
        
        SessionFactory factory = ClusterJHelper.getSessionFactory(props);
        Session session = factory.getSession();

We are getting below error -

Exception in thread "main" com.mysql.clusterj.ClusterJFatalUserException: No instance for service com.mysql.clusterj.SessionFactoryService could be found. Make sure that there is a file META-INF/services/com.mysql.clusterj.SessionFactoryService in your class path naming the factory class.
	at com.mysql.clusterj.ClusterJHelper.getServiceInstance(ClusterJHelper.java:171)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:78)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:64)
	at AppicationMain.main(AppicationMain.java:26)

We tried creating META-INF/services/com.mysql.clusterj.SessionFactoryService in resources directory and then it gave below issue -

Exception in thread "main" java.lang.NullPointerException
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at com.mysql.clusterj.ClusterJHelper.getServiceInstances(ClusterJHelper.java:126)
	at com.mysql.clusterj.ClusterJHelper.getServiceInstance(ClusterJHelper.java:165)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:78)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:64)
	at AppicationMain.main(AppicationMain.java:26)

We also tried by adding SessionFactory (com.mysql.clusterj.SessionFactory), SessionFactoryService and Session class in META-INF/services/com.mysql.clusterj.SessionFactoryService file. Then it gives below error -

Exception in thread "main" com.mysql.clusterj.ClusterJFatalUserException: No instance for service com.mysql.clusterj.SessionFactoryService could be found. Make sure that there is a file META-INF/services/com.mysql.clusterj.SessionFactoryService in your class path naming the factory class.java.lang.NoSuchMethodException: com.mysql.clusterj.SessionFactory.<init>()
	at com.mysql.clusterj.ClusterJHelper.getServiceInstance(ClusterJHelper.java:171)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:78)
	at com.mysql.clusterj.ClusterJHelper.getSessionFactory(ClusterJHelper.java:64)
	at AppicationMain.main(AppicationMain.java:26)

Is there something we are missing here? Let me know if need any more inputs.

First comment is that I would recommend that you set node id in the properties object.
This is set with (e.g. setting node id to 67):
props.put(“com.mysql.clusterj.connection.pool.nodeids”, “67”);

Make sure that the node id set exists in the config.ini file and make sure
no other program is already using this node id. You can also specify the
host name that can connect to a node id in config.ini.

If you need more than cluster connection you will need multiple node ids,
one can set pool size and the above variable to set the node ids.

The error messages complains about the classpath not containing the object.
So what have you put in the classpath when starting the java program?

The link you supplied also displays how to start the program and what to put into
the classpath, also a reference to the NDB API library (from RonDB installation).

One more thing is to ensure that the ClusterJ jar-file and the NDB API library are both
using the same version. Thus if the ClusterJ jar-file uses RonDB 21.04.1, then ensure
that the NDB API library referred to is also from RonDB 21.04.1.

Version of ClusterJ is 21.04.1 and it is obtained from RonDB installation directory. We have copies clusterj, clusterj-api and lib directory to local to test connection with ClusterJ.
I tried running from command line as java -classpath lib/clusterj-21.04.1.jar:. -Djava.library.path=lib/lib AppicationMain. lib/lib directory contains libndbclient.so and other library files. Running from command line gives following error - com.mysql.clusterj.ClusterJFatalUserException: Attempt to load native library ndbclient from path lib/lib failed with class java.lang.UnsatisfiedLinkError (no ndbclient in java.library.path). Caused by java.lang.UnsatisfiedLinkError:no ndbclient in java.library.path

Earlier I was running using IntelliJ and eventually realized that clusterj jar which is required at runtime was not getting included in classpath. After fixing that, I was getting same issue command line and IDE - no ndbclient in java.library.path.
After some thinking it hit me that ndbclient libraries are running on Centos instances and I’m attempting to use the same on Mac. I’ll probably need libraries built for Mac to work on my local system.

So I tried to create the jar run it directly on mysql instance (Centos) and it worked fine over there.
Also added com.mysql.clusterj.connection.pool.nodeids in my properties. Thanks for that suggestion.

1 Like

One follow-up question on com.mysql.clusterj.connection.pool.nodeids.
Let’s say ClusterJ setup is abstracted through Rest API and we run multiple instances of this service, so in that case we need to make sure that each instance using a different node id, is that correct? Or can we share a node-id value in multiple instances?

It is correct that the NDB API library on Mac cannot use the Linux one.
I am developing on Mac OS X, so should be possible in the future to
also deliver tarballs for Mac OS X. I will add that to my TODO list.

Node ids cannot be shared on multiple instances, you could think of
the node ids as the “IP” address of the nodes in the RonDB cluster.
All messages in RonDB are sent using a triplet of
node id, thread id and module id. Thus each node have to have a
unique node id.

It is possible to run with dynamic node ids (thus not specifying the node
id in the Properties object), in this case there must be
sufficient amount of API nodes slots in the config.ini to handle all
the instances of the service and the MySQL Servers.

With dynamic node ids the RonDB cluster will assign the node id
dynamically from the list of possible node ids to assign. If there is
no free node ids available the ClusterJ will not be able to create
a SessionFactory.

In config.ini one can either specify a hostname for a node id in
which case the node id will only be used for that specific host.
If no hostname is provided the node id can be used by any host.

Regarding Mac OS X libraries they can be built if you set up a build
environment. There are build scripts available in the git tree under
build_scripts/build_script_prod.sh. The CMake script will usually
give good hints on what needs to be installed to make it work.
You will at a minimum need to install CMake and XCode.

Since there is daily development on Mac OS X, it should be
a stable platform to use.

Able to build RonDB on Mac and use those library files (.dylib) in java application to connect via ClusterJ interface.
Thanks for the help.

1 Like