1.25 Facts

Facts are triples in the form {subject, relation, object}. They are stored in a database. To create an empty database call Facts.database(). To query the environment database (global database with all program symbols and operators) use Facts.env_db().

Use Facts.add_tags to add a triple to a database and Facts.remove_tags to remove a triple from a database.

Facts can be queried in order from queries in triples. If you only need one triple you can use Facts.with_tags or Facts.collect_with_tags. If you need a join query you can use Facts.with or Facts.collect_with to query multiple triples at the same time. These functions initialize internally an iterator for the query and then call the iterator in a loop calling a callback function or evaluating the passed block for _macro variants.

You can achieve persistence by calling just one function. Facts.open takes a database and a pathname as arguments and replays the dump and the log in the file and opens the file for appending for logging all transactions.

Transactions make their content atomic. A transaction either end in success or error. In the latter case, the already applied parts of the transaction are rolled back in reverse order. The database is locked read/write during a transaction. Transactions can be nested and are multithread ready with pthread support.

1.25.1 Examples

Create a database and add and remove triples and do a full query (?, ?, ?) :

ikc3> db = Facts.database()
(Ptr) 0x12345678
ikc3> Facts.add_tags(db, "Blade Runner", :is_a, :movie)
true
ikc3> Facts.add_tags(db, "Snow White", :is_a, :movie)
true
ikc3> Facts.remove_tags(db, "Blade Runner", :is_a, :movie)
true
ikc3> Facts.with_tags(db, ?, ?, ?, fn (fact) { puts(inspect(fact)) })
{"Snow White", :is_a, :movie}

Query operators from the global environment :

ikc3> Facts.with(Facts.env_db(), [[op = ?, :is_a, :op],
ikc3>                             [op, :op_sym, sym = ?]], fn (fact) {
ikc3>   puts("#{inspect(sym)} #{inspect(op)}")
ikc3> })

The config module from an HTTPd instance has an example of persistence, this way the database is loaded when the module is loaded :

defmodule Config do
  def db = Facts.database()
  Facts.open(db, "db/app.facts")
end

1.25.2 Network Replication

Facts databases support network replication. When connections are established between databases, all add and remove operations are automatically broadcast to connected peers. This works independently of on-disk persistence (the log).

Connecting to a remote database

Use Facts.connect to connect to a remote facts server:

ikc3> db = Facts.database()
ikc3> Facts.connect(db, "192.168.1.100", "9000")
true

The connection runs a background thread that receives facts from the remote peer and applies them to the local database.

Accepting connections (server mode)

To accept incoming connections, first create a TCP server socket using the Socket module, then use Facts.accept:

ikc3> require Socket
ikc3> db = Facts.database()
ikc3> server = Socket.listen("0.0.0.0", "9000")
ikc3> Facts.accept(db, server)
true

Each accepted connection spawns a background thread for receiving facts.

Closing connections

To close all connections on a database:

ikc3> Facts.close_all(db)

This gracefully shuts down all connection threads and closes the sockets.


Top : KC3 documentation

Previous : 1.24 Variable

Next : 1.26 Named block