Hotloading code

Re-posting this as a new topic in the Nice To know category, as @EricGT suggested.

The beauty of SWI-Prolog - hotloading code

Just along the lines of what has been posted, recently I had a long running process (hours and hours) and I needed to correct a small issue. I couldn’t stop the process. Well…SWI-Prolog came to the rescue: it is able to hot load code on the fly!

Here is a little example.

:- use_module(library(prolog_server)).
:- prolog_server(4333,[]).

longrunning :-
    flag(counter,C,C+1),
	format('~w blippy blops so far~n',[C]),
	sleep(3),
	longrunning.

Run this in one terminal window:

26 ?- longrunning.
...
232306 blippy blops so far
232307 blippy blops so far
232308 blippy blops so far
232309 blippy blops so far
232310 blippy blops so far
232311 blippy blops so far

Now, those numbers are getting hard to read, wouldn’t it be nice if I could just fix the output, printing easier to read numbers, without stopping the process?

Well, SWI-Prolog does it!
In your favorite editor fix the format/2 statement changing this:

	format('~w blippy blops so far~n',[C]),

to this:

	format('~D blippy blops so far~n',[C]),

Save the file, and now we can hotload the code! In another terminal, run this:

$ telnet localhost 4333   % yes, ssh is supported with the libssh addon
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Welcome to the SWI-Prolog server on thread client@localhost.localdomain

1 ?- make.
...

Now look at the output in the first terminal :grin: :

26 ?- longrunning.
...
232306 blippy blops so far
232307 blippy blops so far
232308 blippy blops so far
232309 blippy blops so far
232310 blippy blops so far
232311 blippy blops so far
232312 blippy blops so far
232313 blippy blops so far
232,314 blippy blops so far      % right here the code was hotloaded
232,315 blippy blops so far
232,316 blippy blops so far
232,317 blippy blops so far
232,318 blippy blops so far
232,319 blippy blops so far

I have only been able to do this with erlang in the past.
Certainly, SWI-Prolog is a gem.

3 Likes

thanks great.

How does this work …

In Erlang - at least from what I recently read – there is a mechanism to have two versions loaded concurrently and old and a new version. And, somehow, some code keeps using the old while other starts using the new … and then there is a way to migrate old to new.

I wonder if something similar can be built in prolog around make.

See SWI-Prolog -- Reloading files, active code and threads. Bottom line is that it works pretty much like transactions but for static code rather than dynamic code and uses related but somewhat older techniques. The result is an atomic transition from the old code to the new code. That works fine as log as you do not change the interfaces of the involved predicates (i.e., add, delete or swap arguments, pass incompatible types, etc). You can add/remove and modify clauses. The code completes the current call on the old definition and runs the next on the new. Clause GC reclaims the old clauses when no thread uses them.

Running two versions would require a more complete implementation of the transaction mechanism for static code. It would require the user to tell the system that some goal needs to run with the current definitions. It would allow servers to activate arbitrary source changes, but at the cost of preparing for this in the design of the server. I guess that should wait for someone requiring such features and prepared to invest to make it happen.

4 Likes

hotloading code on the server

Wow, that’s amazing. Great explanation from Jan, too.

Guess all my home server code is going to be in Prolog from now on!

Hotloading (AKA Dynamic software updating (DSU)) also works with SWI-Prolog based web servers.

For example, SWI-Prolog is used to run a web server (http_server/2) and generate the html pages (html_reply_page/2,3). If the Prolog code to generate a reply page for index.html is changed, one might expect the steps to be

  1. halt web server
  2. compile code (think SWI-Prolog make/0)
  3. restart the web server
  4. refresh index.html page

Instead with DSU the steps are

  1. compile code (think SWI-Prolog make/0)
  2. refresh index.html page

It doesn’t always work but when it does is nice because halting the web server cleanly can take several seconds each time.