Still don’t understand your specific use case, maybe this one will hit closer to the mark.
If the requirements are
- Preserve data using assert so that it does not have to be passed back as a parameter.
- Has to have thread safety.
You note it is used for testing, but for this repose that is a requirement that can be discarded.
Use library(persistence).
Here is a real example I recently created.
This is a file with path:
'D:/Cellular Information/Source Code/Prolog/PDF/PDF_persistency.pl'
:- module(
pdf__persistency,
[
exists_name_value/3, % ?Name:atom, ?Hierarchy:list, ?Value:compound
add_name_value/3 % +Name:atom, ?Hierarchy:list, +Value:compound
]
).
:- use_module(library(persistency)).
:- persistent
name_value(name:atom,hierarchy:list,value:compound).
:- initialization(db_attach('D:/Cellular Information/Source Code/Temp/pdf.journal', [])).
exists_name_value(Name,Hierarchy,Value) :-
with_mutex(pdf_db,name_value(Name,Hierarchy,Value)).
add_name_value(Name,Hierarchy,Value) :-
with_mutex(pdf_db,assert_name_value(Name,Hierarchy,Value)).
Here is the code that makes uses of it.
This is in a file with path:
‘D:/Cellular Information/Source Code/Prolog/PDF/PDF__parser.pl’
:- use_module('D:/Cellular Information/Source Code/Prolog/PDF/pdf_persistency.pl').
persist_structures(Trailer_dictionary,Xref,Linear_structure) :-
(
% Does it exist
exists_name_value('Trailer directory',[],Trailer_dictionary)
;
% If not then add it
add_name_value('Trailer directory',[],Trailer_dictionary)
),
(
% Does it exist
exists_name_value('Xref',[],Xref)
;
% If not then add it
add_name_value('Xref',[],Xref)
),
persist_trailer_dictionary(Linear_structure,[],Trailer_dictionary).
Here is a partial list of the contents of:
D:\Cellular Information\Source Code\Temp\pdf.journal
created(1559406518.911974).
assert(name_value('Trailer directory',[],dictionary([key_value(name('Size'),number(78)),key_value(name('Root'),reference(76,0)),key_value(name('Info'),reference(77,0)),key_value(name('ID'),array([hex_number("d8d301b6211e2bc9e7508b45f162d319"),hex_number("d8d301b6211e2bc9e7508b45f162d319")]))]))).
assert(name_value('Xref',[],xref(0,[object(0,0,65535,type(free)),object(1,426961,0,type(in-use)),object(2,16,0,type(in-use)),object(3,4485,0,type(in-use)),object(4,422790,0,type(in-use)),object(5,423567,0,type(in-use)),object(6,424345,0,type(in-use)),object(7,424768,0,type(in-use)),object(8,425611,0,type(in-use)),object(9,400088,0,type(in-use)),object(10,400158,0,type(in-use)),object(11,5215,0,type(in-use)),object(12,427866,0,type(in-use)),object(13,4661,0,type(in-use)),object(14,427042,0,type(in-use)),object(15,5285,0,type(in-use)),object(16,10920,0,type(in-use)),object(17,44189,0,type(in-use)),object(18,427126,0,type(in-use)),object(19,11111,0,type(in-use)),object(20,15716,0,type(in-use)),object(21,51884,0,type(in-use)),object(22,427210,0,type(in-use)),object(23,15907,0,type(in-use)),object(24,17973,0,type(in-use)),object(25,424578,0,type(in-use)),object(26,110066,0,type(in-use)),object(27,427294,0,type(in-use)),object(28,18175,0,type(in-use)),object(29,21552,0,type(in-use)),object(30,256447,0,type(in-use)),object(31,287623,0,type(in-use)),object(32,427378,0,type(in-use)),object(33,21755,0,type(in-use)),object(34,24250,0,type(in-use)),object(35,320180,0,type(in-use)),object(36,356948,0,type(in-use)),object(37,366709,0,type(in-use)),object(38,427462,0,type(in-use)),object(39,24455,0,type(in-use)),object(40,29328,0,type(in-use)),object(41,375685,0,type(in-use)),object(42,427546,0,type(in-use)),object(43,29530,0,type(in-use)),object(44,35517,0,type(in-use)),object(45,427630,0,type(in-use)),object(46,35684,0,type(in-use)),object(47,41042,0,type(in-use)),object(48,427714,0,type(in-use)),object(49,41198,0,type(in-use)),object(50,44043,0,type(in-use)),object(51,399513,0,type(in-use)),object(52,399693,0,type(in-use)),object(53,399792,0,type(in-use)),object(54,399891,0,type(in-use)),object(55,399989,0,type(in-use)),object(56,400226,0,type(in-use)),object(57,400571,0,type(in-use)),object(58,404754,0,type(in-use)),object(59,405195,0,type(in-use)),object(60,411563,0,type(in-use)),object(61,411856,0,type(in-use)),object(62,413215,0,type(in-use)),object(63,413431,0,type(in-use)),object(64,413819,0,type(in-use)),object(65,414385,0,type(in-use)),object(66,422097,0,type(in-use)),object(67,422317,0,type(in-use)),object(68,425787,0,type(in-use)),object(69,426373,0,type(in-use)),object(70,425929,0,type(in-use)),object(71,426666,0,type(in-use)),object(72,425999,0,type(in-use)),object(73,426077,0,type(in-use)),object(74,427798,0,type(in-use)),object(75,427826,0,type(in-use)),object(76,428012,0,type(in-use)),object(77,428082,0,type(in-use))]))).
assert(name_value('Root',['Root'],object(id(76,0),dictionary([key_value(name('Type'),name('Catalog')),key_value(name('Pages'),reference(12,0)),key_value(name('PageLabels'),reference(75,0))])))).
assert(name_value('Pages',['Root','Pages'],object(id(12,0),dictionary([key_value(name('Type'),name('Pages')),key_value(name('Kids'),array([reference(1,0),reference(14,0),reference(18,0),reference(22,0),reference(27,0),reference(32,0),reference(38,0),reference(42,0),reference(45,0),reference(48,0)])),key_value(name('Count'),number(10)),key_value(name('MediaBox'),array([number(0),number(0),number(612),number(792)]))])))).
assert(name_value('Kids',['Root','Pages','Kids'],object(id(1,0),dictionary([key_value(name('Type'),name('Page')),key_value(name('Parent'),reference(12,0)),key_value(name('Resources'),reference(3,0)),key_value(name('Contents'),reference(2,0))])))).
assert(name_value('Resources',['Root','Pages','Kids','Resources'],object(id(3,0),dictionary([key_value(name('ProcSet'),array([name('PDF'),name('Text')])),key_value(name('Font'),dictionary([key_value(name('F1'),reference(4,0)),key_value(name('F2'),reference(5,0)),key_value(name('F3'),reference(6,0)),key_value(name('F5'),reference(7,0)),key_value(name('F6'),reference(8,0))])),key_value(name('ExtGState'),dictionary([key_value(name('GS1'),reference(9,0)),key_value(name('GS2'),reference(10,0))])),key_value(name('ColorSpace'),dictionary([key_value(name('Cs8'),reference(11,0))]))])))).
assert(name_value('F1',['Root','Pages','Kids','Resources','Font','F1'],object(id(4,0),dictionary([key_value(name('Type'),name('Font')),key_value(name('Subtype'),name('Type1')),key_value(name('FirstChar'),number(32)),key_value(name('LastChar'),number(181)),key_value(name('Widths'),array([number(333),number(313),number(552),number(668),number(479),number(896),number(750),number(281),number(354),number(354),number(521),number(667),number(313),number(417),number(313),number(531),number(500),number(500),number(500),number(500),number(500),number(500),number(500),number(500),number(500),number(500),number(313),number(313),number(667),number(667),number(667),number(365),number(927),number(740),number(698),number(740),number(823),number(646),number(594),number(781),number(833),number(365),number(344),number(740),number(604),number(927),number(813),number(844),number(646),number(844),number(771),number(563),number(729),number(771),number(750),number(1000),number(802),number(750),number(750),number(365),number(531),number(365),number(583),number(500),number(333),number(479),number(573),number(490),number(573),number(479),number(323),number(552),number(563),number(292),number(281),number(542),number(271),number(927),number(573),number(573),number(573),number(573),number(396),number(375),number(344),number(573),number(521),number(781),number(531),number(521),number(510),number(396),number(566),number(396),number(521),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(490),number(833),number(333),number(333),number(333),number(333),number(333),number(750),number(333),number(333),number(333),number(333),number(333),number(333),number(333),number(668),number(333),number(333),number(333),number(552)])),key_value(name('Encoding'),name('WinAnsiEncoding')),key_value(name('BaseFont'),name('JONDFF+Bembo-Bold')),key_value(name('FontDescriptor'),reference(56,0))])))).
Also since these structures are rather complex and hard to interpret as single line, using print_term/2 comes in handy.
As you noted that you are looking at b_setval/2 and friends and b_setval/2 reads:
Associate the term Value with the atom Name or replace the currently associated value with Value. If Name does not refer to an existing global variable, a variable with initial value []
is created (the empty list). On backtracking the assignment is reversed.
This example does not implement On backtracking the assignment is reversed.
however library(persistency) notes
The persistent/1 expands each declaration into four predicates:
name(Arg, ...)
assert_name(Arg, ...)
retract_name(Arg, ...)
retractall_name(Arg, ...)
so the requirement might be satisfied by use of retract_name(Arg, ...)
with some added logic 
However if you are using this for testing or learning then possibly you might want to see all variations of the value, in which case there would not be a need to retract on backtracking and instead save each value with a unique seqential value for sorting such as a time stamp using date_time_stamp/2 or sequential values using library(gensym)