Did you know ... Search Documentation:
Pack pcache -- prolog/cache_rocks.pl
PublicShow source

This module implements persistent caching of answers. The inspiration comes from tabled execution where tabled answers are kept as a trie of tries. The outer trie maps goal variants to answer tries and the answer tries provide the answers to a specific goal variant. The library(rocksdb) (and library(bdb)) provide a persistent Key-Value store that can map a term to a term. The term is represented as an external record, basically a binary alternative to write/read. This binary representation is a blob for the key-value store. The representation represents a variant, currently with two limitations:

  1. If the term has internal sharing, it is different from a term without. E.g., A = f(X), B = b(A,A) is a different B than you get from B = b(f(X),f(X)).
  2. If the key is cyclic, it only matches internally equivalent cycles. E.g., A = [a|A] and A = [a,a|A] are considered different.

Ignoring these two issues (which can be fixed), we can use RocksDB or BDB as the outer trie used in tabling. We could use a trie or similar structure for the set of answers, but in this case a list preserves the original order and is more compact. Our database basically maps call variants to a list of answers.

In addition, it does some book keeping. First of all, it uses signature.pl to compute a deep hash of the predicate. A deep hash is an SHA1 hash computed from the clauses of the predicates and all predicates called by it. The original goal, say m:p(a1, ...) is translated into <SHA1>(a1, ...). This implies that changing a predicate or one of the predicates called by it invalidate the cache. Second, it keeps track of partially completed goals and fully completed goals. Re-running a fully completed goal simply retrieves the cached answers. Re-running a partially completed goal first retrieves the cached answers and then re-runs the goal with an offset to compute additional answers, updating the status.

 cache_open(+Directory)
Open an answer cache in Directory. If Directory does not exist, create it as an empty answer store. Otherwise re-open an existing store.
 cached(:Goal)
This predicate is logically equivalent to Goal. However, answers are on the first call collected in a trie and subsequently returned in arbitrary (hash key) order without duplicates.
 cached(:Goal, +Hash)
Get the answers for Goal from an old hashed result. Hash is either the full hash or a shorthash (7 character prefix).
 cache_property(:Goal, ?Property) is nondet
 cache_properties(:Goal, ?Properties:dict) is nondet
True if Property is a properly of the cached answers for Goal. Defined properties are:
count(-Count)
Number of answers
hash(-Hash)
Deep hash of the predicate associated with the goal.
time_cached(-Time)
Time stamp when the cache was created.

The cache_properties/2 variant returns all properties of a cache in a dict using the above keys.

 forget(:Goal)
Forget all cached results that are subsumed by Goal. Typically used as forget(m:p(_,_)) to remove all data cached for p/2. Notably forget(_:_) will destroy the entire cache.
 cache_statistics(?Key)
True when Key is a know statistics about the caching mechanism.
 cache_listing is det
 cache_listing(+Options) is det
List contents of the persistent cache.
 cache_property(:Goal, ?Property) is nondet
 cache_properties(:Goal, ?Properties:dict) is nondet
True if Property is a properly of the cached answers for Goal. Defined properties are:
count(-Count)
Number of answers
hash(-Hash)
Deep hash of the predicate associated with the goal.
time_cached(-Time)
Time stamp when the cache was created.

The cache_properties/2 variant returns all properties of a cache in a dict using the above keys.

 cache_listing is det
 cache_listing(+Options) is det
List contents of the persistent cache.