Category Archives: Software Development

vprintf segfault on Ubuntu Linux 15.10

I have a C program with a ‘print’ function that accepts a format string and variable list of arguments, similar to printf style functions. The function simply prints to stdout and also to a logfile.

void print(const char* format, ...) {
	pthread_mutex_lock(&logfile_mutex);
 
	va_list args;
	va_start(args,format);
 
	vprintf(format,args);
	fflush(stdout);
 
	fprintf(logfile,"%d ",milli_timer());
	vfprintf(logfile,format,args);
	fflush(logfile);
 
	va_end(args);
 
	pthread_mutex_unlock(&logfile_mutex);
}

Everything seemed fine compiling with g++ under Cygwin, but would crash when compiled on Ubuntu Linux 15.10. After a bit of digging I finally spotted the problem in the documentation for vprintf:

Internally, the function retrieves arguments from the list identified by arg as if va_arg was used on it, and thus the state of arg is likely altered by the call.

Apparently this is one of those things that is compiler specific. Since we can’t rely on the state of the arguments list after the first call to vprintf, the solution was simply to use a new arguments list for the second call to vprintf which writes to the log file. Revised function:

void print(const char* format, ...) {
	pthread_mutex_lock(&logfile_mutex);
 
	va_list stdout_args;
	va_start(stdout_args,format);
	vprintf(format,stdout_args);
	fflush(stdout);
	va_end(stdout_args);
 
	va_list log_args;
	va_start(log_args,format);
	fprintf(logfile,"%d ",milli_timer());
	vfprintf(logfile,format,log_args);
	fflush(logfile);
	va_end(log_args);
 
	pthread_mutex_unlock(&logfile_mutex);
}

Hope that helps someone.

local array causes segfault

Recently while working on a C program I was intermittently getting a segfault. The code appeared correct yet it would inexplicably crash, seemingly at random. I compiled the program with the ‘-g’ flag to enable debugging symbols, and discovered I was dealing with the dreaded stack overflow.


Exception: STATUS_STACK_OVERFLOW at rip=00100414BC6

The line of code in question was the declaration of a large local array. Something like:


int foo[REALLY_BIG_NUMBER];

The fix was really simple. I just replaced that line of code with this one:


int* foo = malloc(REALLY_BIG_NUMBER * sizeof(int));
...
// later on...
free(foo); // <--- very important!

That's it. The difference is the area of memory that the data is allocated in. In the former example (the local array), the compiler used stack memory. The stack is an area of memory used for temporary variables created by each function. By allocating a large array, I tried to fit more into the stack than it could accommodate, hence the 'stack overflow'. In the latter example, a different area of memory is used called the heap. The heap is not as tightly managed and is somewhat larger.

chess4j + SQLite

The last time I wrote anything about chess4j, way back in November, I reported that chess4j was using a small in-memory database of opening moves. The program was reading a library of about 500 games from GM Kasparov, which it would do every time the program initialized. Before each move, chess4j would consult this in-memory database to see what moves have been played by Kasparov (or his opponent), and choose between them using a weighted random selection algorithm. The effect of this was that chess4j no longer played the same opening moves, so it added some variability to its online play. It also produced games that were a little more “aesthetic”, or pleasing to look at.

That was a huge step forward, but it had some limitations. Reading all those games takes a little time, so it isn’t really practical to read in more than about 500. It’s also expensive in terms of memory since they are all held in-memory, so there are some limitations there. Finally, it doesn’t leave any room for any learning algorithms since the program is initialized to the same state each time it starts.

To address those issues I needed a solution that persisted data to the disk. In past programs written in C/C++ I’ve created custom file formats and used fseek() and the like to probe it. This time I decided to use a proper database. I had considered MongoDB, mainly just to play around with it, but in the end I decided on SQLite. SQLite is lightweight, reliable, and fast – a perfect fit. (Side note: the primary author of SQLite, Dr. Richard Hipp, was roommates with my graduate school advisor, Dr. Ronnie Smith when they were both working on their PhDs at Duke University. I’ve met him… very nice guy.)

The database table to hold these opening book moves is very simple:

sqlite> .schema book_moves
CREATE TABLE book_moves (key int not null,fromsq int not null,tosq int not null,frequency int default 1,wins int,losses int,draws int);
CREATE INDEX idx_book_moves_key on book_moves(key);

Really, the only fields that are necessary are the first three: key, fromsq, and tosq. ‘key’ is used as a signature for a position. That is, every possible chess position has its own unique value for ‘key’. (I’m not going to get into the algorithm to do that in this post, just accept that it’s true!) ‘fromsq’ and ‘tosq’ are probably self explanatory – they represent the square the piece is moving from and the square it’s moving to. So, if we want to probe the opening book to see what moves it contains from any given position, we just produce the value of “key”, then perform the query:

select fromsq,tosq,frequency,wins,losses,draws from book_moves where key=?

‘frequency’ is a count of how many times the move was encountered as the opening book was constructed. This is what makes the random weighted selection possible. The idea here is that, if move A was encountered 10 times as often as move B, then chances are it’s a better move and I should play it roughly 10 times as often. This approach helps keep a stray “bad move” that may have found its way into the book database from getting on equal footing with good moves.

Finally, we have ‘wins’, ‘losses’, and ‘draws’. Each time chess4j completes a game, it increments the appropriate counter for the moves it played from the opening book (not moves the opponent played). It doesn’t actually do anything with this information yet, but future versions will probably use the information to avoid any moves it consistently loses with.

So, that’s a brief description of the implementation. To seed the database I found an online collection of about 50,000 games played by Master level players or above. The database I’m using currently has nearly 150,000 moves.

Watching chess4j play with this opening book is really fun. Since it doesn’t have to “think,” it plays almost instantaneously when it has a response in the opening book. Below is a segment from logfile. Notice how it begins with “c4”, then parses the opponent’s response “g8f6” and responds with “b1c3”. The frequency counts on the moves it encounters in its opening book gradually diminishes until it has no book response for “c7c6” and has to start thinking on its own.


# parsing: level 0 5 3
# level: 0, 5, 3
# setting increment to 3000 ms.
# parsing: name Pepo2424
# opponent is: Pepo2424
# parsing: rating 1989 1611
# parsing: time 30000
#time : 300000
# parsing: otim 30000
# parsing: go
# book move: BookMove [move=c2c4, frequency=8939]
move c2c4
# parsing: time 30300
#time : 303000
# parsing: otim 30100
# parsing: usermove g8f6
# book move: BookMove [move=b1c3, frequency=1520]
move b1c3
# parsing: time 30600
#time : 306000
# parsing: otim 30100
# parsing: usermove g7g6
# book move: BookMove [move=g2g3, frequency=182]
move g2g3
# parsing: time 30900
#time : 309000
# parsing: otim 30300
# parsing: usermove f8g7
# book move: BookMove [move=f1g2, frequency=225]
move f1g2
# parsing: time 31200
#time : 312000
# parsing: otim 30400
# parsing: usermove d7d6
# book move: BookMove [move=e2e4, frequency=24]
move e2e4
# parsing: time 31400
#time : 314000
# parsing: otim 30500
# parsing: usermove e7e5
# book move: BookMove [move=g1e2, frequency=5]
move g1e2
# parsing: time 31700
#time : 317000
# parsing: otim 30600
# parsing: usermove e8g8
# book move: BookMove [move=e1g1, frequency=12]
move e1g1
# parsing: time 32000
#time : 320000
# parsing: otim 30200
# parsing: usermove c8e6
# book move: BookMove [move=d2d3, frequency=7]
move d2d3
# parsing: time 32300
#time : 323000
# parsing: otim 30300
# parsing: usermove c7c6
# transposition table initialized with 1048576 entries.
# time remaining: 323000, increment: 3000, allotted time: 15920
1 -183 1 2 c3d5
1 -1 3 4 c3b1
1 4 4 6 c3a4
1 17 4 10 f1e1
1 20 4 12 h2h3
1 22 4 14 h2h4
1 22 6 39 h2h4
2 7 6 78 h2h4 b8d7
2 12 12 230 d1b3 b7b5
2 12 12 246 d1b3 b7b5
3 17 21 368 d1b3 b7b5 h2h4
3 17 28 1500 d1b3 b7b5 h2h4
4 7 45 3541 d1b3 d8c7 h2h4 b8d7
4 7 79 5825 d1b3 d8c7 h2h4 b8d7
5 12 121 9522 d1b3 d8c7 h2h4 b8d7 a2a4
5 12 139 15133 d1b3 d8c7 h2h4 b8d7 a2a4
6 7 190 23677 d1b3 d8c7 h2h4 b8d7 a2a4 d7c5
6 9 293 38345 h2h4 b8d7 a2a4 a7a6 f2f4 h7h5
6 9 339 64469 h2h4 b8d7 a2a4 a7a6 f2f4 h7h5
7 10 440 97805 h2h4 b8d7 a2a4 a7a5 b2b3 d7c5 f2f4
7 10 640 172694 h2h4 b8d7 a2a4 a7a5 b2b3 d7c5 f2f4
8 7 817 243868 h2h4 b8d7 a2a4 a7a5 f2f4 d7c5 f4e5 d6e5
# hash probes: 628514
# hash hits: 58960 (9.38%)
# hash collisions: 31636 (5.03%)
# fail highs: 32795 (5.22%)
# fail lows: 2422 (0.39%)
# exact scores: 37 (0.01%)
move h2h4

-----SNIP-----

# parsing: result 1-0 {Pepo2424 resigns}

This improvement was a lot of fun to implement and it’s a lot of fun to watch. chess4j’s online opponents seem to like it too:

Ara61 says: Thank you for the great game!

I’ve also made some great improvements to the engine’s evaluation routine, but that will be the subject of another post very soon! And, as always the latest development code is available from the project website. These changes are not included in the last official “release” but will be in the 3.0 release coming within the next few weeks.

Swafford Consulting Hired for TrACER-R Project

I’m very pleased and excited to announce that Swafford Consulting has been selected by IVIR Inc. (Information Visualization and Innovative Research) to rewrite and expand the Training/Test Assessment Capabilities and Reporting for Research (TrACER-R) System.

The following information has been publicly released by IVIR and posted on this website with permission from them.

TrACER is an automated assessment and evaluation system, designed for research and test conduct. It automatically produces test instruments, collects tests data, correlates data and produces both statistical and descriptive analysis for final test reports. The system can be used for any procedure or skill set identified in critical research areas. It produces objective evaluation of subjects, and observer/controller performance for cognitive tasks, psychomotor skills, affective measurement, and decision making performance. It is particularly useful for medical research.

Swafford Consulting has done work for IVIR before, on the F2MC Trainer project .

JBoss 7 – Channel end notification received, closing channel Channel ID (inbound) of Remoting connection to null

As mentioned in a previous post I’ve recently upgraded to JBoss EAP 6.2 / AS 7.1. For a few weeks after the transition a small set of users were complaining about a ‘channel closed’ error. Few errors have driven me crazier than this one. It was not a good time, for me or the users.

After receiving this error the user was unable to do anything in my application; they had to shut it down and restart. In the server logs I was also seeing a steady stream of :


java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling

I try pretty hard to minimize the possibility of bugs. But, every once in a while one does pop up, and when it does I try to reproduce it in a development environment, write a failing test, and then solve the problem. Try as I might, I just could not reproduce this error in a development setup. After some time it became clear that the error had something to do with their environment.

Well, it turned out that about the same time I updated the application servers, the IT staff were busy upgrading firewalls. They pulled a Linux based firewall and replaced it with a Cisco ASA (I can’t remember the exact model). These ASAs are pretty clever. They have some logic built into them to detect when a connection is ‘dead’ and then forcibly closes the connection. What happens is, after about 30 minutes of inactivity the firewall decides that the connection between the application client and the server (which is offsite in a data center) must be dead, so it kills it, unbeknownst to the application. Then, the user goes to do something again, and the dreaded ‘Channel Closed’ error would appear.

You might think that is the end of the story. I wish it were.

Once the problem became clear I knew the solution would be to use some sort of ‘keep alive’ on the connection. And, as it turns out there is a way to do that. Just set this property (either in XML or programmatically as I do here):


clientProp.put("remote.connection.default.connect.options.org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL","60000");

The issue was that I was mixing two different approaches to establishing remote connections, with the consequence being that my ‘heartbeat’ configuration was not taking effect. One method, which appears to be the less superior but better documented approach, is to use remote naming. There is also the EJB Client API, which according to this page is the better approach (though it doesn’t tell how to use it).

Long story short: if you want to use the EJB Client API, then your Context lookup should look something like this:

private static void getContext(String login,String hashedPassword) throws NamingException {
   Properties clientProp = new Properties();
   clientProp.put("endpoint.name", "programmatic-client-endpoint");
   clientProp.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
   clientProp.put("remote.connections", "default");
   clientProp.put("remote.connection.default.port", "4447");
   String namingProvider = System.getProperty("java.naming.provider.url");
   if (namingProvider==null) namingProvider="localhost";
   clientProp.put("remote.connection.default.host", namingProvider); 
   clientProp.put("remote.connection.default.username", login);
   clientProp.put("remote.connection.default.password", hashedPassword);
   cientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
   clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
   clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");
   clientProp.put("remote.connection.default.connect.options.org.jboss.remoting3.RemotingOptions.HEARTBEAT_INTERVAL","60000");
   EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(clientProp);
   ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
   EJBClientContext.setSelector(selector);		
 
   Properties p = new Properties();
   p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
 
   ctx = (Context) new InitialContext(p);
}

In particular please note that the Properties object passed into the InitialContext has just one key/value pair — the one that tells it to use the EJB Client API. All other configuration options should be passed into the PropertiesBasedEJBClientConfiguration. In my case I had some extra/ superfluous “stuff” in the Properties given to the InitialContext, and as a result the heartbeat messages were not going out. I think it had fallen back to using remote naming, but I can’t be sure. Once the extra junk was removed everything started working as expected.

chess4j learns some moves from Kasparov

Ok, “learn” is too strong a word. More accurately, chess4j now has a small opening book database populated with a little over 500 Kasparov games. Before doing any thinking on its own, chess4j will consult this database, and if a move is found it will play it. This has the effect of steering the game into a nice position that a Grandmaster might play fairly quickly, and it also adds some more variation to the opening moves as well.

500 games is not a lot, but at the moment the opening book is all contained in memory. That is, when the program starts it reads through those 500+ games, storing them in internal memory, and holding them in memory for the duration of the program’s execution. The next time it starts, it does it again.

I’m really pretty happy with the way this all came together. Here is the method that initializes this in memory opening book:

private static void initBook() throws Exception {
	OpeningBook book = OpeningBookInMemoryImpl.getInstance();
	FileInputStream fis = new FileInputStream(new File("pgn/Kasparov.pgn"));
	PGNIterator it = new PGNIterator(fis);
 
	PGNGame pgnGame;
	while ((pgnGame = it.next()) != null) {
		book.addToBook(pgnGame);
	}
 
	fis.close();
}

As you can see there are a few key classes that make this all work. First, we need an OpeningBook. OpeningBook is an interface, which in this case is implemented by the Singleton OpeningBookInMemoryImpl. I won’t go into the in memory implementation here, because in the future that will be replaced with something with a persistent datastore behind it (maybe MongoDB). But, I will show the interface it implements:

public interface OpeningBook {
 
	public void addToBook(PGNGame game);
 
	public List<BookMove> getMoves(Board board);
 
	public BookMove getMoveWeightedRandomByFrequency(Board board);
}

Pretty simple at the moment, and likely to be expanded. The key points are that you can add a move to the book, or get a list of BookMoves in a given position, or you can get a single BookMove using a weighted random selection algorithm.

Now that we have an OpeningBook, we need something that is capable of reading through a Portable Game Notation (PGN) file, producing a sequence of PGNGame objects.

PGNGame is really just a data object so I won’t show the code here. It really just encapsulates a game, which we can think of as a series of PGN tags, a list of moves, and a result (win, loss, draw).

The PGNIterator class is a little more interesting though. Since some of these PGN files get fairly large (40-50 mb is not unusual), it’s best to take a ‘streaming’ approach to processing them. Hence, if you look back at the initBook() method, you’ll notice the constructor for PGNIterator is given a FileInputStream. (It will accept any type of InputStream, which it uses internally to create a BufferedReader.)

Here is the next() method of PGNIterator :

public PGNGame next() throws IOException, ParseException, IllegalMoveException {
 
	PGNParser parser = new PGNParser();
	String nextGame = getNextPGN();
 
	if (nextGame != null) {
		return parser.parseGame(nextGame);
	}
 
	return null;
}

I’m glossing over a few details here but hopefully that gets the point across. The call to getNextPGN() looks far enough ahead in the stream to capture the String representation of a game, or returns NULL if it can’t (probably because it hit the end of the file). It then uses this PGNParser to convert the String into a PGNGame. As you might imagine PGNParser uses some regular expression stuff that frankly made my head hurt a little. Finally, we saw above that the PGNGame is added to the opening book.

All of this is part of the 3.0 development so it’s not in the latest release, but the source code is available (along with several unit tests) so if you’re the developer type feel free to check it out from the project website on SourceForge .

JBoss 7.x remoting + security-domain

I just recently updated an application to Red Hat’s EAP 6.2.0 platform, which uses the JBoss 7.3 Application Server under the hood. I’ve been a JBoss user for a long time now. In fact, this application started life on JBoss 3.something, and I (sometimes with the help of other devs) have seen it upgraded to every major version of JBoss since. The migration from 6 to 7 is hands down the most difficult to perform. Well, not that it’s really all that difficult, so we’ll just say time consuming. It took a good week to get everything right.

I’ll have more to say about the migration path soon, but one specific area that I think warrants special attention is the security subsystem.

The application has several components to it, one being a Java Swing client that uses Remote Method Invocation. The client has its own log in screen and used the UsernamePasswordHandler class and the ClientLoginModule from JBoss Security packages. Something like this:


UsernamePasswordHandler handler = new UsernamePasswordHandler(username, MD5.hash(password).toCharArray());
LoginContext lc = new LoginContext("MYCONTEXT", handler));
lc.login();

That’s all pretty simple really. The UsernamePasswordHandler is, well, a callback handler that handles NameCallbacks and PasswordCallbacks by setting the values to what you passed into the constructor. We just pass that handler into the LoginContext, which is backed by the default ‘ClientLogniModule’, which just sets the security principal and credential to what’s handed to it by the handler. When ‘login’ is invoked the username and (hashed) password are authenticated against whatever login-module is configured on the server side, which in my case is a DatabaseServerLoginModule.

Unfortunately this became a bit more complicated as a result of this migration. For reasons I don’t understand neither the UsernamePasswordHandler callback nor the ClientLoginModule are available in JBoss 7, nor can I find any classes with similar functionality. It’s not very difficult to implement your own, and in fact that’s what I had to do, but the fact that I had to is … annoying!

Another big change in JBoss 7 is that you can’t even get an InitialContext to do any JNDI lookups without authentication. In other words, you can’t simply just do ‘new InitialContext()’ any longer. I’m not talking about executing remote methods on an EJB here, I mean at the transport layer – the remoting connector itself requires authentication. Here is the configuration :


<subsystem xmlns="urn:jboss:domain:remoting:1.1">
<connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
</subsystem>

See that bit about the ‘ApplicationRealm’ ? That’s the security realm. Within the security realm you must supply a configuration for user authentication. As far as I can tell you can either authenticate against what is called a ‘local user’ (an account you create with the JBoss ‘add-user.sh or add-user.bat’ scripts, that applies to the entire server), or you hand it all off to a JAAS module. Since I have multiple applications running on the server that all have different sets of users, I opted for the latter. Here is the configuration for the ApplicationRealm security realm:


<security-realm name="ApplicationRealm" >
<authentication >
<jaas name="MySecurityDomain"/>
</authentication>
</security-realm>

Now, this is where it gets really good. As I just said, I have multiple applications that all have a their own sets of users. However, the remoting connector is bound to a single security realm, and the security realm to a single JAAS module. I do not believe it’s an option to create multiple remoting connectors, each on its own port, which means that a single JAAS module needs to handle authentication for all applications that run on the server. I’m really hoping I’m just missing something here, but if I am then it’s due to inadequate documentation.

Anyway, I had one last hurdle to jump through. Since a single JAAS module was going to have to authenticate all users, I needed a way to deal with the possibility that there might be different users with the same name in different applications, or , the same user might exist in different applications, have the same password in each, but have different roles. In other words, I need to be sure we’re authenticating against the correct database for the application the user is logging into! So, it’s not enough to just pass over a user name and password any longer — we need the application (or context, or domain if you like) in addition. And then we need to use that context to query against the proper database.

To get the context I just appended it to the user name. So, instead of ‘james.swafford’ the principal is now ‘james.swafford@somedomain’. Easy enough. Now, how to do the authentication itself? I can think of two ways to do this.

I’ve always used the ‘out of the box’ Database Login Module on the server side. If we wanted to use that and had just one application to worry about, the configuration would look something like this:


<security-domain name="MySecurityDomain">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:jboss/SomeDS"/>
<module-option name="principalsQuery" value="select md5passwd from users where login = ? and active=TRUE"/>
<module-option name="rolesQuery" value="select securityroles.role,'Roles' from securityroles inner join users_roles on securityroles.roleid=users_roles.role_id inner join users on users_roles.user_id=users.user_id where login =?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>

Since I have multiple applications, I had to do something a little different. One trick would be to chain multiple login modules together, making each of them ‘sufficient’ instead of required. To do that you’d just have to change the queries to take the context into account.


<authentication>
<login-module code="Database" flag="sufficient">
<module-option name="dsJndiName" value="java:jboss/App1DS"/>
<module-option name="principalsQuery" value="select md5passwd from users where login || '@app1' = ? and active=TRUE"/>
<module-option name="rolesQuery" value="select securityroles.role,'Roles' from securityroles inner join users_roles on securityroles.roleid=users_roles.role_id inner join users on users_roles.user_id=users.user_id where login || '@app1' =?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module name="Database-2" code="Database" flag="sufficient">
<module-option name="dsJndiName" value="java:jboss/App2DS"/>
<module-option name="principalsQuery" value="select md5passwd from users where login || '@app2' = ? and active=TRUE"/>
<module-option name="rolesQuery" value="select securityroles.role,'Roles' from securityroles inner join users_roles on securityroles.roleid=users_roles.role_id inner join users on users_roles.user_id=users.user_id where login || '@app2' =?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>

That works OK and is easy to do, but the drawback is that the app server is going to cycle through all of those modules until one successfully authenticates or they all fail. That is potentially a lot extra querying. Another, probably better solution would be to create a CustomLoginModule that is clever enough to use the context to determine which data source to query.

None of this was all that difficult but it is different and took a little time to learn. Hopefully this will help someone out there save a little time.

chess4j gets a little smarter

Over the holidays I managed to find a little time to do some work on chess4j. It felt really good to dust the codebase off and make some improvements that have had real impact on playing strength.

Up to this point, I have not really focused on playing strength at all. The official release number is 1.2. The focus of the entire initial release (well, the entire 1.x series of releases) has been to create a Winboard compatible program that is rock solid in terms of reliability, and to do so in a test driven manner, meaning a high percentage of the code is covered by unit tests, with some functional tests thrown in for good measure. That goal was accomplished. chess4j has played literally thousands of games on the Internet Chess Club, and it never crashes. It loses a lot! But, it never crashes.

The goal of the 2.x series will be to implement some well known search improvements. This probably will not include parallel or distributed search just yet, just ways to make the single threaded search more efficient. The focus will be on intelligently ordering moves to reduce the branching factor, implementing a capture-only search towards the leaf nodes, extending promising lines, and pruning back less promising lines.

Over the holidays I accomplished the following:

  • added the ability to process test suites, which included a FEN parser, in order to help measure the impact of search improvements
  • implemented a transposition table using an “always replace” strategy.
  • modified the search loop to order moves instead of just playing them in the order they were generated (the only exception to this is it was playing the previous PV first). Now it plays the previous PV, followed by any move suggested by the transposition table, followed by promotions and then all captures, with captures sorted by the well known MVV/LVA algorithm.
  • made a couple of obvious speed/efficiency improvements

I haven’t gotten to the point where I need to be too scientific about measuring the impact of improvements yet. But, there’s no doubt those changes have had a dramatic impact. Before, chess4j’s blitz rating on ICC was typically in the 1100-1200 range. As I type this, it has a blitz rating of 1419. That’s still very, very weak, and far far below Prophet’s former strength, but the point is those changes are having the desired effect!

All of this has been committed to the Sourceforge account, so anyone is free to peek at the code. The official release doesn’t include these changes yet, and probably won’t for several months, but the code is committed for my developer friends who’d like to get a sneak peek at the changes coming in the 2.x line.

The project website: http://chess4j.sourceforge.net/

JBoss + HornetMQ + Encrypted FS + AIO

I wrestled with an …. interesting issue today that sunk most of my morning. I was working on an EJB3 application with a local installation of JBoss 6.1. In fact, I worked on the same application last Friday. Today, however, when I started the server I was greeted with this:

16:23:28,800 ERROR [org.hornetq.ra.inflow.HornetQActivation] Unable to reconnect org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.hornetq.ra.HornetQResourceAdapter@4076fc9 destination= destinationType=javax.jms.Queue ack=Auto-acknowledge durable=false clientID=null user=null maxSession=15): HornetQException[errorCode=2 message=Cannot connect to server(s). Tried with all available servers.]
at org.hornetq.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:619) [:6.1.0.Final]
at org.hornetq.ra.inflow.HornetQActivation.setupSession(HornetQActivation.java:352) [:6.1.0.Final]
at org.hornetq.ra.inflow.HornetQActivation.setup(HornetQActivation.java:290) [:6.1.0.Final]

So, I did what any software developer would and ran to Google. Google, unfortunately, didn’t give me much. I wrestled with it for longer than I should have, feeling stumped, when finally I found towards the top of the log :

10:12:20,837 INFO [AIOFileLockNodeManager] Waiting to obtain live lock
10:12:20,837 INFO [AIOFileLockNodeManager] Live Server Obtained live lock
10:12:21,159 SEVERE [HornetQServerImpl] Failure in initialisation: HornetQException[errorCode=205 message=Can’t open file]
at org.hornetq.core.asyncio.impl.AsynchronousFileImpl.init(Native Method) [:6.1.0.Final]

This was me: “Uhm, what? Is this a permissions issue? But I haven’t touched this configuration and it was just working!!! #$)**!@!”

With that additional information I turned back to Google, and this time found the issue. On Linux systems (I am running Linux Mint) with libaio installed, JBoss will attempt to use AIO for direct and asynchronous file operations. Basically, it’s a performance optimization that bypasses the file system cache in favor of very low level file operations. HOWEVER, if you are on an ENCRYPTED file system (which I am), then this breaks.

That was great, but if it worked Friday, and I haven’t updated the config, then what gives? Well, I did install MySQL over the weekend – and it turns out that MySQL on Ubuntu based systems does install libaio. So, in short, though the configuration hasn’t changed, the environment did.

Finally, I discovered a solution – just configure JBoss to not use AIO. I haven’t used it up until now anyway, but now I had to explictly tell it not to. This can be done in /deploy/hornetq/hornetq-configuration.xml with one line:

< journal-type > NIO < /journal-type >

Hopefully that saves someone out there a little trouble. Probably me in 6 or 12 months from now. 🙂

chess4j 1.2 is released!

chess4j 1.2 is in the wild. There hasn’t been any new development lately in terms of new features or playing strength, but I have put some effort into improving code quality using the excellent Sonar Source tools. Minimal cyclomatic complexity. No circular package dependencies. No critical or major violations. Over 80% test coverage and over 99% rules compliance (the only minor violations being some bogus magic number stuff).

Check it out! —

Sonar Stats

Next on the road map is to wrap up just a bit more testing, playing around with some new Java 7 features to create a parallel performance test, and finally to incorporate some Scala. Fun times ahead!

You can visit the chess4j website on SourceForge here: http://chess4j.sourceforge.net/ .

Enjoy!