View source with raw comments or as raw
   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)  2015, 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(bdb,
  37          [ bdb_init/1,                 % +Options
  38            bdb_init/2,                 % -Environment, +Options
  39            bdb_close_environment/1,    % +Environment
  40            bdb_current_environment/1,  % -Environment
  41            bdb_environment_property/2, % ?Environment, ?Property
  42
  43            bdb_open/4,                 % +File, +Mode, -Handle, +Options
  44            bdb_close/1,                % +Handle
  45            bdb_closeall/0,             %
  46            bdb_current/1,              % -DB
  47
  48            bdb_put/3,                  % +DB, +Key, +Value
  49            bdb_del/3,                  % +DB, +Key, ?Value
  50            bdb_delall/3,               % +DB, +Key, +Value
  51            bdb_enum/3,                 % +DB, -Key, -Value
  52            bdb_get/3,                  % +DB, +Key, -Value
  53            bdb_getall/3,               % +DB, +Key, -ValueList
  54
  55            bdb_transaction/1,          % :Goal
  56            bdb_transaction/2,          % :Goal, +Environment
  57
  58            bdb_version/1               % -Version
  59          ]).
  60:- use_foreign_library(foreign(bdb4pl)).
  61:- meta_predicate
  62    bdb_transaction(0),
  63    bdb_transaction(+, 0).
  64
  65/** <module> Berkeley DB interface
  66
  67This  package  realises  a  binding  to  _Berkeley  DB_,  originally  by
  68[Sleepycat   Software](http://www.sleepycat.com/),   now    managed   by
  69[Oracle](http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html).
  70The DB library implements modular support  for   the  bottom layers of a
  71database. In can be configured  for   single-threaded  access to a file,
  72multi-threaded access with  transactions,  remote   access  as  well  as
  73database replication.
  74
  75Berkeley DB is an _embedded_ database. This implies the library provides
  76access to a file containing one or more database tables. The Berkeley DB
  77database tables are always _binary_, mapping a   _key_ to a _value_. The
  78SWI-Prolog interface to Berkeley DB allows for fast storage of arbitrary
  79Prolog terms including cycles and constraints in the database.
  80
  81Accessing a database consists of four steps:
  82
  83    1. Initialise the default DB environment using bdb_init/1 or
  84       create an explicit DB environment using bdb_init/2. This
  85       step is optional, providing simple non-transactional file access
  86       when omitted.
  87    2. Open a database using bdb_open/4, returning a handle to the
  88       database.
  89    3. Accessing the data using bdb_put/3, bdb_get/3, etc.
  90    4. Closing a database using bdb_close/1. When omitted, all open
  91       databases are closed on program halt (see at_halt/1).
  92
  93*Errors* reported by the underlying database  are mapped to an exception
  94of the form error(bdb(Code,Message,Object), _), where  `Code` is an atom
  95for well known errors and an integer   for less known ones. `Message` is
  96the return from the db_strerror()  function   and  `Object`  is the most
  97related Prolog object, typically  a   database  or  database environment
  98handle. If `Code` is  an  atom,  it   is  the  lowercase  version of the
  99associated C macro after  string  the   =|DB_|=  prefix.  Currently  the
 100following atom-typed codes are  defined: `lock_deadlock`, `runrecovery`,
 101`notfound`,    `keyempty`,    `keyexist`,      `lock_notgranted`     and
 102`secondary_bad`.
 103*/
 104
 105%!  bdb_init(+Options) is det.
 106%!  bdb_init(-Environment, +Options) is det.
 107%
 108%   Initialise  a  DB  _environment_.    The   predicate  bdb_init/1
 109%   initialises the _default_ environment,  while bdb_init/2 creates
 110%   an explicit environment that can be   passed to bdb_open/4 using
 111%   the environment(+Environment) option. If   bdb_init/1 is called,
 112%   it must be called before the first  call to bdb_open/4 that uses
 113%   the default environment.  If  bdb_init/1   is  not  called,  the
 114%   default environment can only handle  plain   files  and does not
 115%   support multiple threads, locking, crash recovery, etc.
 116%
 117%   Initializing a BDB environment always   requires  the home(+Dir)
 118%   option. If the environment contains   no databases, the argument
 119%   create(true) must be supplied as well.
 120%
 121%   The currently supported options are listed   below.  The name of
 122%   the boolean options are derived from   the  DB flags by dropping
 123%   the  =DB_=  prefix  and  using  lowercase,  e.g.  =DB_INIT_LOCK=
 124%   becomes `init_lock`. For details, please refer to the DB manual.
 125%
 126%     - create(+Bool)
 127%       If `true`, create any underlying file as required. By
 128%       default, no new files are created. This option should be
 129%       set for prograns that create new databases.
 130%     - failchk(+Bool)
 131%     - home(+Home)
 132%       Specify the DB home directory, the directory holding the
 133%       database files.  The directory must exist prior to calling
 134%       these predicates.
 135%     - init_lock(+Bool)
 136%       Enable locking (=DB_INIT_LOCK=).  Implied if transactions
 137%       are used.
 138%     - init_log(+Bool)
 139%       Enable logging the DB modifications (=DB_INIT_LOG=). Logging
 140%       enables recovery of databases in case of system failure.
 141%       Normally it is used in combination with transactions.
 142%     - init_mpool(+Bool)
 143%       Initialize memory pool.  Impicit if mp_size(+Size) or
 144%       mp_mmapsize(+Size) is specified.
 145%     - init_rep(+Bool)
 146%       Init database replication.  The rest of the replication
 147%       logic is not yet supported.
 148%     - init_txn(+Bool)
 149%       Init transactions.  Implies init_log(true).
 150%     - lockdown(+Bool)
 151%     - mp_size(+Integer)
 152%     - mp_mmapsize(+Integer)
 153%       Control memory pool handling (=DB_INIT_MPOOL=). The
 154%       `mp_size` option sets the memory-pool used for
 155%       caching, while the `mp_mmapsize` controls the maximum size
 156%       of a DB file mapped entirely into memory.
 157%     - private(+Bool)
 158%     - recover(+Bool)
 159%       Perform recovery before opening the database.
 160%     - recover_fatal(+Bool)
 161%       Perform fatal recovery before opening the database.
 162%     - register(+Bool)
 163%     - server(+Host, [+ServerOptions])
 164%       Initialise the DB package for accessing a remote
 165%       database. Host specifies the name of the machine running
 166%       `berkeley_db_svc`. Optionally additional options may be
 167%       specified:
 168%       - server_timeout(+Seconds)
 169%         Specify the timeout time the server uses to determine
 170%         that the client has gone. This implies the server will
 171%         terminate the connection to this client if this client
 172%         does not issue any requests for the indicated time.
 173%       - client_timeout(+Seconds)
 174%         Specify the time the client waits for the server to
 175%         handle a request.
 176%     - system_mem(+Bool)
 177%     - transactions(+Bool)
 178%       Enable transactions, providing atomicy of changes and
 179%       security. Implies logging and locking. See
 180%       bdb_transaction/1.
 181%     - thread(+Bool)
 182%       Make the environment accessible from multiple threads.
 183%     - thread_count(+Integer)
 184%       Declare an approximate number of threads in the database
 185%       environment.  See =|DB_ENV->set_thread_count()|=.
 186%     - use_environ(+Bool)
 187%     - use_environ_root(+Bool)
 188%     - config(+ListOfConfig)
 189%       Specify a list of configuration options, each option is of
 190%       the form Name(Value).  Currently unused.
 191
 192%!  bdb_close_environment(+Environment) is det.
 193%
 194%   Close a database environment that   was explicitly created using
 195%   bdb_init/2.
 196
 197%!  bdb_current_environment(-Environment) is nondet.
 198%
 199%   True when Environment is a currently known environment.
 200
 201bdb_current_environment(Environment) :-
 202    bdb_current_environment_(Environment),
 203    bdb_is_open_env(Environment).
 204
 205bdb_current_environment_(Env) :-
 206    (   var(Env)
 207    ->  (   Env = default
 208        ;   current_blob(Env, bdb_env)
 209        )
 210    ;   (   Env == default
 211        ->  true
 212        ;   current_blob(Env, bdb_env)
 213        )
 214    ).
 215
 216%!  bdb_environment_property(?Environment, ?Property) is nondet.
 217%
 218%   True when Property is a property of Environment.  Defined
 219%   properties are all boolean options defined with bdb_init/2
 220%   and the following options:
 221%
 222%     - home(-Path)
 223%       Path is the absolute path name for the directory used
 224%       as database environment.
 225%     - open(-Boolean)
 226%       True if the environment is open.
 227
 228bdb_environment_property(Env, Property) :-
 229    bdb_current_environment_(Env),
 230    (   bdb_is_open_env(Env)
 231    ->  (   var(Property)
 232        ->  env_property(Property),
 233            bdb_env_property_(Env, Property)
 234        ;   bdb_env_property_(Env, Property)
 235        )
 236    ;   Property = open(false)
 237    ).
 238
 239bdb_env_property_(Env, home(Home)) :-
 240    !,
 241    bdb_env_property(Env, home(Home0)),
 242    prolog_to_os_filename(Home, Home0).
 243bdb_env_property_(Env, Prop) :-
 244    bdb_env_property(Env, Prop).
 245
 246env_property(open(true)).
 247env_property(home(_)).
 248env_property(init_lock(_)).
 249env_property(init_log(_)).
 250env_property(init_mpool(_)).
 251env_property(init_rep(_)).
 252env_property(init_txn(_)).
 253env_property(recover(_)).
 254env_property(recover_fatal(_)).
 255env_property(use_environ(_)).
 256env_property(use_environ_root(_)).
 257env_property(create(_)).
 258env_property(lockdown(_)).
 259env_property(failchk(_)).
 260env_property(private(_)).
 261env_property(register(_)).
 262env_property(system_mem(_)).
 263env_property(thread(_)).
 264
 265
 266%!  bdb_open(+File, +Mode, -DB, +Options) is det.
 267%
 268%   Open File holding a database. Mode   is one of `read`, providing
 269%   read-only  access  or  `update`,  providing  read/write  access.
 270%   Options is a list of options.   Supported options are below. The
 271%   boolean options are  passed  as   flags  to  =|DB->open()|=. The
 272%   option name is derived  from  the   flag  name  by stripping the
 273%   =|DB_|=  prefix  and  converting  to  lower  case.  Consult  the
 274%   Berkeley DB documentation for details.
 275%
 276%     - auto_commit(+Boolean)
 277%       Open the database in a transaction.  Ensures no database
 278%       is created in case of failure.
 279%     - create(+Boolean)
 280%       Create a new database of the database does not exist.
 281%     - dup(+Boolean)
 282%       Do/do not allow for duplicate values on the same key.
 283%       Default is not to allow for duplicates.
 284%     - excl(+Boolean)
 285%       Combined with create(true), fail if the database already
 286%       exists.
 287%     - multiversion(+Boolean)
 288%       Open the database with support for multiversion concurrency
 289%       control.  The flag is passed, but no further support is
 290%       provided yet.
 291%     - nommap(+Boolean)
 292%       Do not map this database into process memory.
 293%     - rdonly(+Boolean)
 294%       Open the database for reading only.
 295%     - read_uncommitted(+Boolean)
 296%       Read operations on the database may request the return of
 297%       modified but not yet committed data. This flag must be
 298%       specified on all DB handles used to perform dirty reads or
 299%       database updates, otherwise requests for dirty reads may not
 300%       be honored and the read may block.
 301%     - thread(+Boolean)
 302%       Enable access to the database handle from multiple threads.
 303%       This is default if the corresponding flag is specified for
 304%       the environment.
 305%     - truncate(+Boolean)
 306%       When specified, truncate the underlying file, i.e., start
 307%       with an empty database.
 308%     - database(+Name)
 309%       If File contains multiple databases, address the named
 310%       database in the file. A DB file can only consist of multiple
 311%       databases if the bdb_open/4 call that created it specified
 312%       this argument. Each database in the file has its own
 313%       characteristics.
 314%     - environment(+Environment)
 315%       Specify a database environment created using bdb_init/2.
 316%     - key(+Type)
 317%     - value(+Type)
 318%       Specify the type of the key or value. Allowed values are:
 319%       - term
 320%         Key/Value is a Prolog term (default). This type allows for
 321%         representing arbitrary Prolog data in both keys and value.
 322%         The representation is space-efficient, but Prolog
 323%         specific. See PL_record_external() in the SWI-Prolog
 324%         Reference Manual for details on the representation. The
 325%         other representations are more neutral. This implies they
 326%         are more stable and sharing the DB with other languages is
 327%         feasible.
 328%       - atom
 329%         Key/Value is an atom. The text is represented as a
 330%         UTF-8 string and its length.
 331%       - c_blob
 332%         Key/Value is a blob (sequence of bytes).  On output,
 333%         a Prolog string is used.  The input is either a Prolog
 334%         string or an atom holding only characters in the range
 335%         [0..255].
 336%       - c_string
 337%         Key/Value is an atom. The text is represented as a C
 338%         0-terminated UTF-8 string.
 339%       - c_long
 340%         Key/Value is an integer. The value is represented as a
 341%         native C long in machine byte-order.
 342%
 343%   @arg DB is unified with a _blob_ of type `db`. Database handles
 344%   are subject to atom garbage collection.
 345%   @error permission_error(access, bdb_environment, Env) if an
 346%   environment is not thread-enabled and accessed from multiple
 347%   threads.
 348
 349%!  bdb_close(+DB) is det.
 350%
 351%   Close BerkeleyDB database indicated by DB. DB becomes invalid
 352%   after this operation.  An attempt to access a closed database
 353%   is detected reliably and results in a permission_error
 354%   exception.
 355
 356%!  bdb_put(+DB, +Key, +Value) is det.
 357%
 358%   Add a new key-value pair to the   database. If the database does
 359%   not allow for duplicates the   possible previous associated with
 360%   Key is replaced by Value.
 361
 362%!  bdb_del(+DB, ?Key, ?Value) is nondet.
 363%
 364%   Delete the first matching key-value pair   from the database. If
 365%   the  database  allows  for   duplicates,    this   predicate  is
 366%   non-deterministic, otherwise it is   _semidet_.  The enumeration
 367%   performed by this predicate is the   same  as for bdb_get/3. See
 368%   also bdb_delall/3.
 369
 370%!  bdb_delall(+DB, +Key, ?Value) is det.
 371%
 372%   Delete all matching key-value  pairs   from  the  database. With
 373%   unbound Value the key and all values are removed efficiently.
 374
 375bdb_delall(DB, Key, Value) :-
 376    var(Value),
 377    !,
 378    bdb_del(DB, Key).               % this is much faster
 379bdb_delall(DB, Key, Value) :-
 380    (   bdb_del(DB, Key, Value),
 381        fail
 382    ;   true
 383    ).
 384
 385%!  bdb_get(+DB, ?Key, -Value) is nondet.
 386%
 387%   Query the database. If the database   allows for duplicates this
 388%   predicate is non-deterministic, otherwise it  is _semidet_. Note
 389%   that if Key is  a  term  this   matches  stored  keys  that  are
 390%   _variants_ of Key, *not*  unification.   See  =@=/2. Thus, after
 391%   bdb_put(DB, f(X), 42), we get the following query results:
 392%
 393%     - bdb_get(DB, f(Y), V) binds Value to `42`, while `Y` is left
 394%       unbound.
 395%     - bdb_get(DB, f(a), V) _fails_.
 396%     - bdb_enum(DB, f(a), V) succeeds, but does not perform any
 397%       indexing, i.e., it enumerates all key-value pairs and
 398%       performs the unification.
 399
 400%!  bdb_enum(+DB, -Key, -Value)
 401%
 402%   Enumerate the whole database, unifying   the  key-value pairs to
 403%   Key and Value.  Though  this  predicate   can  be  used  with an
 404%   instantiated Key to enumerate only the   keys unifying with Key,
 405%   no indexing is used by bdb_enum/3.
 406
 407%!  bdb_getall(+DB, +Key, -Values) is semidet.
 408%
 409%   Get all values associated with Key. Fails   if  the key does not
 410%   exist (as bagof/3).
 411
 412%!  bdb_current(?DB) is nondet.
 413%
 414%   True when DB is a handle to a currently open database.
 415
 416bdb_current(DB) :-
 417    current_blob(DB, bdb),
 418    bdb_is_open(DB).
 419
 420%!  bdb_closeall is det.
 421%
 422%   Close all currently open  databases   and  environments. This is
 423%   called automatically after  loading  this   library  on  process
 424%   terminatation using at_halt/1.
 425
 426bdb_closeall :-
 427    close_databases,
 428    close_environments.
 429
 430close_databases :-
 431    forall(bdb_current(DB),
 432           catch(bdb_close(DB),
 433                 E,
 434                 print_message(warning, E))).
 435
 436close_environments :-
 437    forall(bdb_current_environment(DB),
 438           catch(bdb_close_environment(DB),
 439                 E,
 440                 print_message(warning, E))).
 441
 442terminate_bdb :-
 443    (   current_predicate(bdb_init/1)       % library was loaded ok
 444    ->  bdb_closeall
 445    ;   true
 446    ).
 447
 448:- at_halt(terminate_bdb).
 449
 450%!  bdb_transaction(:Goal) is semidet.
 451%!  bdb_transaction(+Environment, :Goal) is semidet.
 452%
 453%   Start a transaction, execute Goal and terminate the transaction.
 454%   Only if Goal succeeds, the  transaction   is  commited.  If Goal
 455%   fails or raises an exception,  the   transaction  is aborted and
 456%   bdb_transaction/1 either fails or  rethrows   the  exception. Of
 457%   special interest is the exception
 458%
 459%     ==
 460%     error(package(db, deadlock), _)
 461%     ==
 462%
 463%   This exception indicates a deadlock was raised  by one of the DB
 464%   predicates. Deadlocks may arise if multiple processes or threads
 465%   access  the  same  keys   in   a    different   order.   The  DB
 466%   infra-structure causes one of  the   processes  involved  in the
 467%   deadlock to abort its transaction. This   process  may choose to
 468%   restart the transaction.
 469%
 470%   For example, a DB application  may   define  `{Goal}` to realise
 471%   transactions and restart these automatically   is  a deadlock is
 472%   raised:
 473%
 474%     ==
 475%     {Goal} :-
 476%         catch(bdb_transaction(Goal), E, true),
 477%         (   var(E)
 478%         ->  true
 479%         ;   E = error(package(db, deadlock), _)
 480%         ->  {Goal}
 481%         ;   throw(E)
 482%         ).
 483%     ==
 484%
 485%   @arg Environment defines the environment to which the
 486%   transaction applies.  If omitted, the default environment
 487%   is used.  See bdb_init/1 and bdb_init/2.
 488
 489%!  bdb_version(-Version:integer) is det.
 490%
 491%   True when Version identifies the database version.  Version
 492%   is an integer defined as:
 493%
 494%     ==
 495%     DB_VERSION_MAJOR*10000 +
 496%     DB_VERSION_MINOR*100   +
 497%     DB_VERSION_PATCH
 498%     ==
 499
 500
 501                 /*******************************
 502                 *             MESSAGES         *
 503                 *******************************/
 504
 505:- multifile
 506    prolog:message/3.
 507
 508prolog:message(error(bdb(Code, Message, Obj), _)) -->
 509    [ 'BDB: Error ~w on ~p: ~w'-[Code, Obj, Message] ].