1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2003-2013, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(rdf_edit, 37 [ rdfe_assert/3, % Sub, Pred, Obj 38 rdfe_assert/4, % Sub, Pred, Obj, PayLoad 39 rdfe_retractall/3, % Sub, Pred, Obj 40 rdfe_retractall/4, % Sub, Pred, Obj, PayLoad 41 rdfe_update/4, % Sub, Pred, Obj, +Action 42 rdfe_update/5, % Sub, Pred, Obj, +PayLoad, +Action 43 rdfe_load/1, % +File 44 rdfe_load/2, % +File, +Options 45 rdfe_delete/1, % +Resource 46 47 rdfe_register_ns/2, % +Id, +URI 48 rdfe_unregister_ns/2, % +Id, +URI 49 50 rdfe_reset/0, % clear everything 51 52 rdfe_transaction/1, % :Goal 53 rdfe_transaction/2, % :Goal, +Name 54 rdfe_transaction_member/2, % +Transactions, -Action 55 rdfe_transaction_name/2, % +Transactions, -Name 56 rdfe_set_transaction_name/1,% +Name 57 58 rdfe_set_watermark/1, % +Name 59 60 rdfe_undo/0, % 61 rdfe_redo/0, 62 rdfe_can_undo/1, % -TID 63 rdfe_can_redo/1, % -TID 64 65 rdfe_set_file_property/2, % +File, +Property 66 rdfe_get_file_property/2, % ?File, ?Property 67 68 rdfe_is_modified/1, % ?File 69 rdfe_clear_modified/1, % +File 70 71 rdfe_open_journal/2, % +File, +Mode 72 rdfe_close_journal/0, 73 rdfe_replay_journal/1, % +File 74 rdfe_current_journal/1, % -Path 75 76 rdfe_snapshot_file/1 % -File 77 ]). 78:- use_module(rdf_db). 79:- use_module(library(broadcast)). 80:- use_module(library(lists)). 81:- use_module(library(debug)). 82:- use_module(library(uri)). 83 84:- meta_predicate 85 rdfe_transaction( ), 86 rdfe_transaction( , ). 87 88:- predicate_options(rdfe_load/2, 2, 89 [pass_to(rdf_db:rdf_load/2, 2)]). 90 91:- dynamic 92 undo_log/5, % TID, Action, Subj, Pred, Obj 93 current_transaction/1, % TID 94 transaction_name/2, % TID, Name 95 undo_marker/2, % Mode, TID 96 journal/3, % Path, Mode, Stream 97 snapshot_file/1. % File
113:- rdf_meta 114 rdfe_assert(r,r,o), 115 rdfe_assert(r,r,o,+), 116 rdfe_retractall(r,r,o), 117 rdfe_update(r,r,o,t), 118 rdfe_delete(r), 119 rdfe_transaction(:), 120 rdfe_transaction(:, +). 121 122 123 /******************************* 124 * BASIC EDIT OPERATIONS * 125 *******************************/ 126 127rdfe_assert(Subject, Predicate, Object) :- 128 rdfe_assert(Subject, Predicate, Object, user). 129 130rdfe_assert(Subject, Predicate, Object, PayLoad) :- 131 rdf_assert(Subject, Predicate, Object, PayLoad), 132 rdfe_current_transaction(TID), 133 assert_action(TID, assert(PayLoad), Subject, Predicate, Object), 134 journal(assert(TID, Subject, Predicate, Object, PayLoad)). 135 136rdfe_retractall(Subject, Predicate, Object) :- 137 rdfe_retractall(Subject, Predicate, Object, _). 138 139rdfe_retractall(Subject, Predicate, Object, PayLoad) :- 140 rdfe_current_transaction(TID), 141 ( rdf(Subject, Predicate, Object, PayLoad), 142 assert_action(TID, retract(PayLoad), Subject, Predicate, Object), 143 journal(retract(TID, Subject, Predicate, Object, PayLoad)), 144 fail 145 ; true 146 ), 147 rdf_retractall(Subject, Predicate, Object, PayLoad).
! subject(+Subject)
! predicate(+Predicate)
! object(+Object)
! source(+Source)
158rdfe_update(Subject, Predicate, Object, Action) :- 159 rdfe_current_transaction(TID), 160 rdf_update(Subject, Predicate, Object, Action), 161 ( Action = object(New) 162 -> assert_action(TID, object(Object), Subject, Predicate, New) 163 ; Action = predicate(New) 164 -> assert_action(TID, predicate(Predicate), Subject, New, Object) 165 ; Action = subject(New) 166 -> assert_action(TID, subject(Subject), New, Predicate, Object) 167 ; Action = source(New) 168 -> forall(rdf(Subject, Predicate, Object, PayLoad), 169 assert_action(TID, source(PayLoad, New), 170 Subject, Predicate, Object)) 171 ), 172 journal(update(TID, Subject, Predicate, Object, Action)). 173 174rdfe_update(Subject, Predicate, Object, PayLoad, Action) :- 175 rdfe_current_transaction(TID), 176 rdf_update(Subject, Predicate, Object, PayLoad, Action), 177 ( Action = source(New) 178 -> assert_action(TID, source(PayLoad, New), 179 Subject, Predicate, Object) 180 ; throw(tbd) % source is used internally 181 ), 182 journal(update(TID, Subject, Predicate, Object, PayLoad, Action)).
190rdfe_delete(Subject) :- 191 rdfe_transaction(delete(Subject)). 192 193delete(Subject) :- 194 rdfe_retractall(Subject, _, _), 195 rdfe_retractall(_, Subject, _), 196 rdfe_retractall(_, _, Subject). 197 198 199 /******************************* 200 * FILE HANDLING * 201 *******************************/
209rdfe_load(File) :- 210 rdfe_load(File, []). 211 212 213rdfe_load(File, Options) :- 214 rdfe_current_transaction(TID), 215 absolute_file_name(File, 216 [ access(read), 217 extensions([rdf,rdfs,owl,'']) 218 ], Path), 219 rdf_load(Path, 220 [ graph(Graph), 221 modified(Modified) 222 | Options 223 ]), 224 ( Modified == not_modified 225 -> true 226 ; absolute_file_name('.', PWD), 227 size_file(Path, Size), 228 ( Modified = last_modified(Stamp) 229 -> true 230 ; time_file(Path, Stamp) 231 ), 232 SecTime is round(Stamp), 233 rdf_statistics(triples_by_graph(Graph, Triples)), 234 rdf_md5(Graph, MD5), 235 assert_action(TID, load_file(Path), -, -, -), 236 journal(rdf_load(TID, 237 Path, 238 [ pwd(PWD), 239 size(Size), 240 modified(SecTime), 241 triples(Triples), 242 md5(MD5), 243 from(File) 244 ])), 245 ensure_snapshot(Path) 246 ). 247 248 249rdfe_unload(Path) :- 250 rdfe_current_transaction(TID), 251 rdf_unload(Path), 252 assert_action(TID, unload_file(Path), -, -, -), 253 journal(rdf_unload(TID, Path)).
262ensure_snapshot(Path) :- 263 rdfe_current_journal(_), 264 rdf_md5(Path, MD5), 265 ( snapshot_file(Path, MD5, 266 [ access(read), 267 file_errors(fail) 268 ], 269 File) 270 -> debug(snapshot, 'Existing snapshot for ~w on ~w', [Path, File]) 271 ; snapshot_file(Path, MD5, 272 [ access(write) 273 ], 274 File), 275 debug(snapshot, 'Saving snapshot for ~w to ~w', [Path, File]), 276 rdf_save_db(File, Path) 277 ), 278 assert(snapshot_file(File)). 279ensure_snapshot(_).
289load_snapshot(Source, Path) :-
290 statistics(cputime, T0),
291 rdf_load_db(Path),
292 statistics(cputime, T1),
293 Time is T1 - T0,
294 rdf_statistics(triples_by_graph(Source, Triples)),
295 rdf_md5(Source, MD5),
296 % 1e10: modified far in the future
297 assert(rdf_db:rdf_source(Source, 1e12, Triples, MD5)),
298 print_message(informational,
299 rdf(loaded(Source, Triples, snapshot(Time)))),
300 assert(snapshot_file(Path)).
307snapshot_file(Path, MD5, Options, SnapShot) :-
308 file_base_name(Path, Base),
309 atomic_list_concat([Base, @, MD5], File),
310 absolute_file_name(snapshot(File),
311 [ extensions([trp])
312 | Options
313 ],
314 SnapShot).
324rdfe_snapshot_file(File) :- 325 snapshot_file(File). 326 327 328 /******************************* 329 * NAMESPACE HANDLING * 330 *******************************/ 331 332:- dynamic 333 system_ns/2. 334:- volatile 335 system_ns/2.
rdf_register_ns(Id, URI)
341rdfe_register_ns(Id, URI) :- 342 rdf_db:ns(Id, URI), 343 !. 344rdfe_register_ns(Id, URI) :- 345 save_system_ns, 346 rdfe_current_transaction(TID), 347 rdf_register_ns(Id, URI), 348 broadcast(rdf_ns(register(Id, URI))), 349 assert_action(TID, ns(register(Id, URI)), -, -, -), 350 journal(ns(TID, register(Id, URI))). 351 352rdfe_unregister_ns(Id, URI) :- 353 save_system_ns, 354 rdfe_current_transaction(TID), 355 retractall(rdf_db:ns(Id, URI)), 356 broadcast(rdf_ns(unregister(Id, URI))), 357 assert_action(TID, ns(unregister(Id, URI)), -, -, -), 358 journal(ns(TID, unregister(Id, URI))). 359 360% rdfe_register_ns/0 361% 362% Reset namespaces to the state they where before usage of the 363% rdf_edit layer. 364 365rdfe_reset_ns :- 366 ( system_ns(_, _) 367 -> retractall(rdf_db:ns(Id, URI)), 368 forall(system_ns(Id, URI), assert(rdb_db:ns(Id, URI))) 369 ; true 370 ). 371 372save_system_ns :- 373 system_ns(_, _), 374 !. % already done 375save_system_ns :- 376 forall(rdf_db:ns(Id, URI), assert(system_ns(Id, URI))). 377 378 379 /******************************* 380 * TRANSACTIONS * 381 *******************************/
389rdfe_transaction(Goal) :- 390 rdfe_transaction(Goal, []). 391rdfe_transaction(Goal, Name) :- 392 rdfe_begin_transaction(Name), 393 ( catch(Goal, E, true) 394 -> ( var(E) 395 -> check_file_protection(Error), 396 ( var(Error) 397 -> rdfe_commit 398 ; rdfe_rollback, 399 throw(Error) 400 ) 401 ; rdfe_rollback, 402 throw(E) 403 ) 404 ; rdfe_rollback, 405 fail 406 ).
413rdfe_begin_transaction(Name) :- 414 current_transaction(TID), % nested transaction 415 !, 416 append(TID, [1], TID2), 417 asserta(current_transaction(TID2)), 418 assert(transaction_name(TID2, Name)). 419rdfe_begin_transaction(Name) :- % toplevel transaction 420 flag(rdf_edit_tid, TID, TID+1), 421 asserta(current_transaction([TID])), 422 assert(transaction_name(TID, Name)). 423 424rdfe_current_transaction(TID) :- 425 current_transaction(TID), 426 !. 427rdfe_current_transaction(_) :- 428 throw(error(existence_error(rdf_transaction, _), _)). 429 430rdfe_commit :- 431 retract(current_transaction(TID)), 432 !, 433 retractall(undo_marker(_, _)), 434 ( rdfe_transaction_member(TID, _) 435 -> get_time(Time), % transaction is not empty 436 journal(commit(TID, Time)), 437 ( TID = [Id] 438 -> broadcast(rdf_transaction(Id)) 439 ; true 440 ) 441 ; true 442 ). 443 444rdfe_rollback :- 445 retract(current_transaction(TID)), 446 !, 447 journal(rollback(TID)), 448 rollback(TID).
457rollback(TID) :- 458 append(TID, _, Id), 459 ( retract(undo_log(Id, Action, Subject, Predicate, Object)), 460 ( rollback(Action, Subject, Predicate, Object) 461 -> fail 462 ; print_message(error, 463 rdf_undo_failed(undo(Action, Subject, 464 Predicate, Object))), 465 fail 466 ) 467 ; true 468 ). 469 470rollback(assert(PayLoad), Subject, Predicate, Object) :- 471 !, 472 rdf_retractall(Subject, Predicate, Object, PayLoad). 473rollback(retract(PayLoad), Subject, Predicate, Object) :- 474 !, 475 rdf_assert(Subject, Predicate, Object, PayLoad). 476rollback(Action, Subject, Predicate, Object) :- 477 action(Action), 478 !, 479 rdf_update(Subject, Predicate, Object, Action). 480 481 482assert_action(TID, Action, Subject, Predicate, Object) :- 483 asserta(undo_log(TID, Action, Subject, Predicate, Object)).
490undo(TID) :- 491 append(TID, _, Id), 492 ( retract(undo_log(Id, Action, Subject, Predicate, Object)), 493 ( undo(Action, Subject, Predicate, Object) 494 -> fail 495 ; print_message(warning, 496 rdf_undo_failed(undo(Action, Subject, 497 Predicate, Object))), 498 fail 499 ) 500 ; true 501 ). 502 503undo(assert(PayLoad), Subject, Predicate, Object) :- 504 !, 505 rdfe_retractall(Subject, Predicate, Object, PayLoad). 506undo(retract(PayLoad), Subject, Predicate, Object) :- 507 !, 508 rdfe_assert(Subject, Predicate, Object, PayLoad). 509undo(source(Old, New), Subject, Predicate, Object) :- 510 !, 511 rdfe_update(Subject, Predicate, Object, Old, source(New)). 512undo(ns(Action), -, -, -) :- 513 !, 514 ( Action = register(Id, URI) 515 -> rdfe_unregister_ns(Id, URI) 516 ; Action = unregister(Id, URI) 517 -> rdfe_register_ns(Id, URI) 518 ). 519undo(load_file(Path), -, -, -) :- 520 !, 521 rdfe_unload(Path). 522undo(unload_file(Path), -, -, -) :- 523 !, 524 rdfe_load(Path). 525undo(Action, Subject, Predicate, Object) :- 526 action(Action), 527 !, 528 rdfe_update(Subject, Predicate, Object, Action). 529 530action(subject(_)). 531action(predicate(_)). 532action(object(_)).
540rdfe_undo :- 541 undo_marker(undo, TID), 542 !, 543 ( undo_previous(TID, UnDone) 544 -> retractall(undo_marker(_, _)), 545 assert(undo_marker(undo, UnDone)), 546 broadcast(rdf_undo(undo, UnDone)) 547 ; fail % start of undo log 548 ). 549rdfe_undo :- 550 retract(undo_marker(redo, _)), 551 !, 552 last_transaction(TID), 553 undo_previous(TID, UnDone), 554 assert(undo_marker(undo, UnDone)), 555 broadcast(rdf_undo(undo, UnDone)). 556rdfe_undo :- 557 last_transaction(TID), 558 undo_previous(TID, UnDone), 559 assert(undo_marker(undo, UnDone)), 560 broadcast(rdf_undo(undo, UnDone)). 561 562find_previous_undo(-1, _) :- 563 !, 564 fail. 565find_previous_undo(TID, TID) :- 566 undo_log([TID|_], _, _, _, _), 567 !. 568find_previous_undo(TID0, TID) :- 569 TID1 is TID0 - 1, 570 find_previous_undo(TID1, TID). 571 572undo_previous(TID, Undone) :- 573 find_previous_undo(TID, Undone), 574 rdfe_transaction(undo([Undone])). 575 576last_transaction(TID) :- 577 undo_log([TID|_], _, _, _, _), 578 !.
584rdfe_redo :-
585 ( retract(undo_marker(undo, _))
586 -> last_transaction(TID),
587 undo_previous(TID, UnDone),
588 assert(undo_marker(redo, UnDone)),
589 broadcast(rdf_undo(redo, UnDone))
590 ; retract(undo_marker(redo, TID))
591 -> undo_previous(TID, UnDone),
592 assert(undo_marker(redo, UnDone)),
593 broadcast(rdf_undo(redo, UnDone))
594 ; true
595 ).
605rdfe_can_redo(Redo) :- 606 undo_marker(undo, _), 607 !, 608 last_transaction(TID), 609 find_previous_undo(TID, Redo). 610rdfe_can_redo(Redo) :- 611 undo_marker(redo, TID), 612 find_previous_undo(TID, Redo). 613 614rdfe_can_undo(Undo) :- % continue undo 615 undo_marker(undo, TID), 616 !, 617 find_previous_undo(TID, Undo). 618rdfe_can_undo(Undo) :- % start undo 619 last_transaction(TID), 620 find_previous_undo(TID, Undo).
626rdfe_transaction_name(TID, Name) :-
627 transaction_name(TID, Name),
628 Name \== [].
634rdfe_set_transaction_name(Name) :-
635 current_transaction(TID),
636 !,
637 assert(transaction_name(TID, Name)).
644rdfe_transaction_member(TID, Member) :- 645 ( integer(TID) 646 -> Id = [TID|_] 647 ; append(TID, _, Id) 648 ), 649 undo_log(Id, Action, Subject, Predicate, Object), 650 user_transaction_member(Action, Subject, Predicate, Object, Member). 651 652user_transaction_member(assert(_), Subject, Predicate, Object, 653 assert(Subject, Predicate, Object)) :- !. 654user_transaction_member(retract(_), Subject, Predicate, Object, 655 retract(Subject, Predicate, Object)) :- !. 656user_transaction_member(load_file(Path), -, -, -, 657 file(load(Path))) :- !. 658user_transaction_member(unload_file(Path), -, -, -, 659 file(unload(Path))) :- !. 660user_transaction_member(Update, Subject, Predicate, Object, 661 update(Subject, Predicate, Object, Update)). 662 663 664 /******************************* 665 * PROTECTION * 666 *******************************/ 667 668:- dynamic 669 rdf_source_permission/2, % file, ro/rw 670 rdf_current_default_file/2. % file, all/fallback
access(ro/rw)
default(all/fallback)
679rdfe_set_file_property(File, access(Access)) :- 680 !, 681 to_uri(File, URL), 682 retractall(rdf_source_permission(URL, _)), 683 assert(rdf_source_permission(URL, Access)), 684 broadcast(rdf_file_property(URL, access(Access))). 685rdfe_set_file_property(File, default(Type)) :- 686 to_uri(File, URL), 687 rdfe_set_file_property(URL, access(rw)), % must be writeable 688 retractall(rdf_current_default_file(_,_)), 689 assert(rdf_current_default_file(URL, Type)), 690 broadcast(rdf_file_property(URL, default(Type))).
698rdfe_get_file_property(FileOrURL, access(Access)) :- 699 ( ground(FileOrURL) 700 -> to_uri(FileOrURL, URL) 701 ; rdf_source(_DB, URL), 702 FileOrURL = URL 703 ), 704 ( rdf_source_permission(URL, Access0) 705 -> Access0 = Access 706 ; uri_file_name(URL, File), 707 access_file(File, write) 708 -> assert(rdf_source_permission(URL, rw)), 709 Access = rw 710 ; assert(rdf_source_permission(URL, ro)), 711 Access = ro 712 ). 713rdfe_get_file_property(FileOrURL, default(Default)) :- 714 ground(FileOrURL), 715 to_uri(FileOrURL, URL), 716 ( rdf_current_default_file(URL, Default) 717 -> true 718 ; FileOrURL = user, 719 Default = fallback 720 ). 721rdfe_get_file_property(URL, default(Default)) :- 722 ( rdf_current_default_file(URL, Default) 723 -> true 724 ; URL = user, 725 Default = fallback 726 ).
733check_file_protection(Error) :-
734 ( rdfe_get_file_property(File, access(ro)),
735 rdfe_is_modified(File)
736 -> Error = error(permission_error(modify, source, File), triple20)
737 ; true
738 ).
745to_uri(URL, URL) :- 746 uri_components(URL, Components), 747 uri_data(scheme, Components, Scheme), 748 nonvar(Scheme), 749 uri_scheme(Scheme), 750 !. 751to_uri(File, URL) :- 752 uri_file_name(URL, File). 753 754 755uri_scheme(file). 756uri_scheme(http). 757uri_scheme(https). 758uri_scheme(ftp). 759uri_scheme(ftps). 760 761 762 /******************************* 763 * MODIFIED * 764 *******************************/
771rdfe_is_modified(Source) :- 772 rdf_source(Graph, Source), 773 rdf_graph_property(Graph, modified(true)). 774 775 776rdfe_clear_modified :- 777 forall(rdf_graph(File), 778 rdfe_clear_modified(File)).
784rdfe_clear_modified(Graph) :- 785 rdf_set_graph(Graph, modified(false)). 786 787 788 /******************************* 789 * WATERMARKS * 790 *******************************/
797rdfe_set_watermark(Name) :- 798 rdfe_current_transaction(TID), 799 assert_action(TID, watermark(Name), -, -, -), 800 journal(watermark(TID, Name)). 801 802 803 /******************************* 804 * RESET * 805 *******************************/
811rdfe_reset :-
812 rdfe_reset_journal,
813 rdfe_reset_ns,
814 rdfe_reset_undo,
815 rdf_reset_db,
816 broadcast(rdf_reset).
822rdfe_reset_journal :- 823 ( rdfe_current_journal(_) 824 -> rdfe_close_journal 825 ; true 826 ). 827 828rdfe_reset_undo :- 829 retractall(undo_log(_,_,_,_,_)), 830 retractall(current_transaction(_)), 831 retractall(transaction_name(_,_)), 832 retractall(undo_marker(_,_)), 833 retractall(snapshot_file(_)). 834 835% close possible open journal at exit. Using a Prolog hook 836% guarantees closure, even for most crashes. 837 838:- at_halt(rdfe_reset_journal). 839 840 841 /******************************* 842 * JOURNALLING * 843 *******************************/ 844 845journal_version(1).
861rdfe_open_journal(_, _) :- % already open 862 journal(_, _, _), 863 !. 864rdfe_open_journal(File, read) :- 865 !, 866 absolute_file_name(File, 867 [ extensions([rdfj, '']), 868 access(read) 869 ], 870 Path), 871 rdfe_replay_journal(Path), 872 rdfe_clear_modified. 873rdfe_open_journal(File, write) :- 874 !, 875 absolute_file_name(File, 876 [ extensions([rdfj, '']), 877 access(write) 878 ], 879 Path), 880 open(Path, write, Stream, [close_on_abort(false)]), 881 assert(journal(Path, write, Stream)), 882 get_time(T), 883 journal_open(start, T). 884rdfe_open_journal(File, append) :- 885 working_directory(CWD, CWD), 886 absolute_file_name(File, 887 [ extensions([rdfj, '']), 888 relative_to(CWD), 889 access(write) 890 ], 891 Path), 892 ( exists_file(Path) 893 -> rdfe_replay_journal(Path), 894 rdfe_clear_modified, 895 get_time(T), 896 assert(journal(Path, append(T), [])) 897 ; rdfe_open_journal(Path, write) 898 ). 899 900 901journal_open(Type, Time) :- 902 journal_comment(Type, Time), 903 SecTime is round(Time), 904 journal_version(Version), 905 Start =.. [ Type, [ time(SecTime), 906 version(Version) 907 ] 908 ], 909 journal(Start), 910 broadcast(rdf_journal(Start)). 911 912journal_comment(start, Time) :- 913 journal(_, _, Stream), 914 format_time(string(String), '%+', Time), 915 format(Stream, 916 '/* Triple20 Journal File\n\n \c 917 Created: ~w\n \c 918 Triple20 by Jan Wielemaker <wielemak@science.uva.nl>\n\n \c 919 EDIT WITH CARE!\n\c 920 */~n~n', [String]). 921journal_comment(resume, Time) :- 922 journal(_, _, Stream), 923 format_time(string(String), '%+', Time), 924 format(Stream, 925 '\n\c 926 /* Resumed: ~w\n\c 927 */~n~n', [String]).
934rdfe_close_journal :-
935 get_time(T),
936 SecTime is round(T),
937 journal(end([ time(SecTime)
938 ])),
939 retract(journal(_, Mode, Stream)),
940 ( Mode = append(_)
941 -> true
942 ; close(Stream)
943 ).
949rdfe_current_journal(Path) :- 950 journal(Path, _Mode, _Stream). 951 952journal(Term) :- 953 journal(Path, append(T), _), 954 !, 955 ( Term = end(_) 956 -> true 957 ; open(Path, append, Stream, [close_on_abort(false)]), 958 retractall(journal(Path, _, _)), 959 assert(journal(Path, append, Stream)), 960 journal_open(resume, T), 961 journal(Term) 962 ). 963journal(Term) :- 964 ( journal(_, _, Stream) 965 -> write_journal(Term, Stream), 966 flush_output(Stream) 967 ; broadcast(rdf_no_journal(Term)) 968 ). 969 970write_journal(commit(TID, Time), Stream) :- 971 !, 972 format(Stream, 'commit(~q, ~2f).~n~n', [TID, Time]). 973write_journal(Term, Stream) :- 974 format(Stream, '~q.~n', [Term]).
983rdfe_replay_journal(File) :- 984 absolute_file_name(File, 985 [ extensions([rdfj, '']), 986 access(read) 987 ], 988 Path), 989 open(Path, read, Stream), 990 replay(Stream), 991 close(Stream). 992 993replay(Stream) :- 994 read(Stream, Term), 995 replay(Term, Stream). 996 997replay(end_of_file, _) :- !. 998replay(start(_Attributes), Stream) :- 999 !, 1000 read(Stream, Term), 1001 replay(Term, Stream). 1002replay(resume(_Attributes), Stream) :- 1003 !, 1004 read(Stream, Term), 1005 replay(Term, Stream). 1006replay(end(_Attributes), Stream) :- 1007 !, 1008 read(Stream, Term), 1009 replay(Term, Stream). 1010replay(Term0, Stream) :- 1011 replay_transaction(Term0, Stream), 1012 read(Stream, Term), 1013 replay(Term, Stream). 1014 1015replay_transaction(Term0, Stream) :- 1016 collect_transaction(Term0, Stream, Transaction, Last), 1017 ( committed_transaction(Last) 1018 -> replay_actions(Transaction) 1019 ; true 1020 ). 1021 1022collect_transaction(End, _, [], End) :- 1023 ends_transaction(End), 1024 !. 1025collect_transaction(A, Stream, [A|T], End) :- 1026 read(Stream, Term), 1027 collect_transaction(Term, Stream, T, End). 1028 1029committed_transaction(commit(_)). 1030committed_transaction(commit(_, _)). 1031 1032ends_transaction(end_of_file). 1033ends_transaction(commit(_)). 1034ends_transaction(commit(_, _)). 1035ends_transaction(rollback(_)). 1036ends_transaction(end(_)). 1037ends_transaction(start(_)). 1038 1039replay_actions([]). 1040replay_actions([H|T]) :- 1041 ( replay_action(H) 1042 -> replay_actions(T) 1043 ; print_message(warning, 1044 rdf_replay_failed(H)), 1045 ( debugging(journal) 1046 -> gtrace, 1047 replay_actions([H|T]) 1048 ; replay_actions(T) 1049 ) 1050 ).
1065replay_action(retract(_, Subject, Predicate, Object, PayLoad)) :- 1066 rdf_retractall(Subject, Predicate, Object, PayLoad). 1067replay_action(assert(_, Subject, Predicate, Object, PayLoad)) :- 1068 rdf_assert(Subject, Predicate, Object, PayLoad). 1069replay_action(update(_, Subject, Predicate, Object, Action)) :- 1070 rdf_update(Subject, Predicate, Object, Action). 1071replay_action(update(_, Subject, Predicate, Object, Payload, Action)) :- 1072 rdf_update(Subject, Predicate, Object, Payload, Action). 1073replay_action(rdf_load(_, File, Options)) :- 1074 memberchk(md5(MD5), Options), 1075 snapshot_file(File, MD5, 1076 [ access(read), 1077 file_errors(fail) 1078 ], 1079 Path), 1080 !, 1081 debug(snapshot, 'Reloading snapshot ~w~n', [Path]), 1082 load_snapshot(File, Path). 1083replay_action(rdf_load(_, File, Options)) :- 1084 find_file(File, Options, Path), 1085 ( memberchk(triples(0), Options), 1086 memberchk(modified(Modified), Options) 1087 -> rdf_retractall(_,_,_,Path:_), 1088 retractall(rdf_db:rdf_source(Path, _, _, _)), % TBD: move 1089 rdf_md5(Path, MD5), 1090 assert(rdf_db:rdf_source(Path, Modified, 0, MD5)) 1091 ; rdf_load(Path) 1092 ). 1093replay_action(rdf_unload(_, Source)) :- 1094 rdf_unload(Source). 1095replay_action(ns(_, register(ID, URI))) :- 1096 !, 1097 rdf_register_ns(ID, URI). 1098replay_action(ns(_, unregister(ID, URI))) :- 1099 retractall(rdf_db:ns(ID, URI)). 1100replay_action(watermark(_, _Name)) :- 1101 true. 1102 1103find_file(File, _, File) :- 1104 exists_file(File), 1105 !. 1106find_file(File, Options, Path) :- 1107 memberchk(pwd(PWD), Options), 1108 make_path(File, PWD, Path), 1109 exists_file(Path), 1110 !.
1116make_path(File, PWD, Path) :- 1117 atom_concat(PWD, /, PWD2), 1118 atom_concat(PWD2, Path, File). 1119 1120 1121 /******************************* 1122 * MESSAGES * 1123 *******************************/ 1124 1125:- multifile 1126 prolog:message/3, 1127 user:message_hook/3. 1128 1129% Catch messages. 1130 1131prologmessage(rdf_replay_failed(Term)) --> 1132 [ 'RDFDB: Replay of ~p failed'-[Term] ]. 1133prologmessage(rdf_undo_failed(Term)) --> 1134 [ 'RDFDB: Undo of ~p failed'-[Term] ]
RDF edit layer
This library provides a number of functions on top of the rdf_db module: