Library(persistancy) and with_mutex: how to use it

I’m looking at the sample code provided in the persistency.pl and do not quite get the logics behind the use of with_mutex.

  1. Why is there with_mutex(user_db, user_role(Name, Role)) in current_user_role/2 but user_role(Name, Role) in set_user_role/2?
  2. Why is there no with_mutex in assert_user_role (add_user/2)?

Related code fragment is attached:

:- module(user_db,
          [ attach_user_db/1,           % +File
            current_user_role/2,        % ?User, ?Role
            add_user/2,                 % +User, +Role
            set_user_role/2             % +User, +Role
          ]).

:- use_module(library(persistency)).

:- persistent
        user_role(name:atom, role:oneof([user,administrator])).

attach_user_db(File) :-
        db_attach(File, []).

%%      current_user_role(+Name, -Role) is semidet.

current_user_role(Name, Role) :-
        with_mutex(user_db, user_role(Name, Role)).

add_user(Name, Role) :-
        assert_user_role(Name, Role).

set_user_role(Name, Role) :-
        user_role(Name, Role), !.
set_user_role(Name, Role) :-
        with_mutex(user_db,
                   (  retractall_user_role(Name, _),
                      assert_user_role(Name, Role))).

The reading needs the with_mutex to avoid reading between the retractall and assert. The first clause of set_user_role/2 can safely check that the desired role is already current, so there is no need to lock there.

SWI-Prolog elementary database operations are thread-safe. So, you can assert/retract stuff and as long as no multiple operations are required to get from one consistent state to the next no locks are needed.

1 Like