Saving and restoring databases and using workspaces

Saving and restoring the current workspace's database

When you start the Arity/Prolog32 interpreter, the database api32.idb is made the "current" database. All database storage and manipulation predicates apply to the current database. When you start a compiled application, the current database is defined by either the name of the module that contains the main/0 predicate, or the value given as the database file name in the environment file. It is possible to create compiled applications that do not specify any current database.

Through the use of the save predicate, you can save the contents of a database. The save/0 predicate will save the contents of the current database. The save/1 predicate will save the contents of the current database under a specified name. The restore/1 predicate can be used to load a previously saved database and make it the current database. The restore/0 predicate will eliminate all changes to the current database since the last time it was saved.

An application can access up to four databases at the same time. The predicates that manage the Arity/Prolog32 workspaces are discussed after the discussion of saving and restoring a single database.

save

save(+Name)

When you make changes to a database, the changes are not permanently saved until you explicitly do so with the save predicate. All changes made to the current database since the last time it was saved are saved in an internal database (.idb) file.

You can save a database under a unique name. In this way, you create a unique idb file which applies only to the current database. You can restore this database by using the restore/1 predicate with the name under which you stored the database.

For example, to save a database under the name bplan, you type the following:

?- save(bplan).

A new .idb file name bplan.idb will be saved.

If you do not supply an extension with Name, then the extension idb is assumed.

The save/0 predicate saves the current database. The save/1 predicate saves the database to the given file and makes that database the current database.

If an application has not loaded a database at startup or called either save/1 or restore/1 with a valid database file name then no .IDB file name is known to the application. If no .IDB file name is known then a call to save/0 will fail. In this case, the database file name returned by the statistics/2 predicate will be the empty atom ('').

restore

restore(+Name)

The restore/0 predicate eliminates all changes made to the current database since the last time it was saved. Thus, if you make changes to a database and you decide that you want to eliminate the changes rather than save them, you use the restore predicate rather than the save predicate.

You can make a particular database the current database by using the restore/1 predicate. You supply the name of the database you want to restore as the argument to restore/1. For example, to make the bplan database the current database, you type the following:

?- restore(bplan).

An .idb file named bplan.idb will be restored.

You can reset the current database to be unnamed and empty by calling restore(0) i.e., restore/1 with the argument instantiated to the integer 0. A database that is unnamed may be reinitialized by a call to restore/0.

Safe saving of databases

Arity/Prolog32 provides the ability to perform safe saves. This is a form of save that is resistant to system crashes. With safe saves the database file will either be completely saved or not saved at all. There can be no inconsistent middle ground. Moreover, in the event of a crash the user of the program need not do anything special - the next restore operation will either roll the database back to its pre-save state or continue the save to completion.

As far as efficiency is concerned, a safe save is about twice as expensive as an unsafe save. This is because each page that must be saved is written twice.

A system flag controls whether or not saves are safe. The flag number is 11. Thus:

sysflag(11, Old, on)      % turns safe saving on
sysflag(11, Old, off)     % turns safe saving off

where the variable Old will be bound to the old state of the flag.

Safe Save Implementation

During safe saves the pages that would normally be written directly to the database file are instead written to a temporary file. This file is named the same as the database file, but has the extension "IDF".

The IDF file is initially created and marked as "invalid". After the safe save is complete the IDF is marked as "valid". Then each page of the IDF file is written to its appropriate place in the database file. If this operation is successful the IDF file is deleted.

On a restore operation (regardless of the state of sysflag 11) the system looks for an IDF file corresponding to the IDB file that it is restoring. If it finds one it checks to see if it is valid. If not, the IDF file is deleted and the restore proceeds. This is the "rollback" case. In this case the save did not reliably complete and we know that we have not written to the IDB file during the save.

If the IDF file is valid then Arity/Prolog32 completes the save by writing the pages to the IDB file. When this operation is complete, the IDF file is deleted. If the safe save operation is terminated due to a crash, then upon restore of the database (usually at initialization of the application) the IDF file will be found and the safe save will again be attempted.

Database Workspaces

With database workspaces an application can access up to four databases at the same time.

Each Prolog thread has associated with it a current workspace number. When the thread is created this number is 0, but it can be changed to

0, 1, 2, or 3, by means of the predicate workspace/2.

workspace(?OldWorkspaceNumber, ?NewWorkspaceNumber)

Lookup or change the workspace associated with the current executing thread.

This predicate uses the query/set convention common to many Prolog predicates. To merely query the current workspace number you call

workspace(X, X)

and to simply set the workspace number to N you call

workspace(_, N)

Each thread keeps track of the current data world and the current partition for each workspace. Therefore, if the following is executed:

?- workspace(_, 0),
    create_world(bar),
    data_world(_, bar),
    dbPartition(_, 20),
    workspace(_, 1),
    data_world(W1, W1),
    dbPartition(P1, P1),
    workspace(_, 0),
    data_world(W2, W2),
    dbPartition(P2, P2),
    write((W1,P1)-(W2,P2)).

the output will be:

(main,0)-(bar,20)
yes

All database predicates execute in a context local to the current workspace, including all versions of the save and restore predicates.

Database refs now refer to a specific term in a specific workspace. As a result you will now see all possible hexadecimal digits as the last digit for a database reference. However all database references that are part of terms stored in a database are assumed to refer to other terms in the SAME database. You CANNOT store a ref from one database in another database. This requirement is necessary in order to ensure that a database can be used in any workspace. If you absolutely must store a "foreign" database ref in a database you must convert it to a long integer and store the integer. Then, when you subsequently use the ref, you must guarantee that the database that it refers to is being used in the same workspace as when the ref was stored.

When using multiple workspaces be aware that all of the active workspaces use the same cache and overflow file. This may affect your setting for the MAXPAGES environment parameter.