User Tools

Site Tools


notes:internals:db

This is an old revision of the document!


Database

If you want to follow along in the code, all of these things are implemented in trie.c, db.c, folk.c, and prelude.tcl.

Folk's database stores all Wishes, Claims, Whens, and Holds. Essentially, it stores everything that happens in Folk. The database works with Statements, either inserting or removing them. All those verbs I mentioned— Wish, When, etc—are functions that insert a Statement into the database by calling the Say function. We'll cover Statement removal later.

Statements

So, what is a Statement? A Statement consists of three parts: the Clause, the child matches, and metadata. Let's start with the Clause: a Clause is an array of words, with each word known as a Term. An example Clause, “the sky is blue”, would become [“the”, “sky”, “is”, “blue”]. We'll cover child matches and metadata in a bit.

Wish and Claim

Let's see what happens when we run Wish.

Wish the sky is blue

When this code runs, it will generate a Clause containing “current-file.folk wishes the sky is blue”. Notice there's a part that was prepended to the beginning, “current-file.folk wishes”. This tells the database what file this Wish came from, and that it's a Wish, not a Claim. This same thing applies to Claim, except with “claims” instead of “wishes”.

When

One other important thing is Whens are also stored in the database. Let's continue with the previous example, except with a When this time:

set foo bar
When /someone/ wishes the sky is /color/ { # code here }

This will insert the following: “when the sky is /color/ { # code here } with environment {foo bar}”. There's quite a bit happening here, so let's break it down:

  1. We add “when” to the beginning, so the database knows this is a When.
  2. We preserve both the query and the code (that's the “the sky is /color/ { # code here }” part).
  3. We add “with environment {foo bar}”, as Tcl doesn't capture scopes. We manually capture the parent scope instead (containing the variable “foo” with the value of “bar”). We'll use this to execute the When later.

Reacting to statements

Now that you're familiar with the concepts at play, let's look at what happens when we insert a When followed by a Wish. I'll italicize the new parts.

set foo bar
When /someone/ wishes the sky is /color/ { # code here }

DB inserts: “when /someone/ wishes the sky is /color/ { # code here } with environment {foo bar}”

Wish the sky is blue

DB inserts: “current-file.folk wishes the sky is blue”

DB queries the database for “when the sky is blue /lambda/ with environment /env/”.

DB gets back the When, and schedules it to be run with this Statement.

Wait wait, what?? That was a lot all at once. Let's break it down.

First, back to the context. We just inserted a Statement, so we need to check if there's any existing Whens that match. So, we do a database query. But what kind of query? Well, let's convert this Wish into what a When would look like if for this Statement. The easiest way to explain this is to just look at a before and after. Before: “current-file.folk wishes the sky is blue” After: “when current-file.folk wishes the sky is blue /lambda/ with environment /env/” Now, if you line up the When term-by-term with the Wish, you'll see these line up beautifully:

when  /someone/          wishes  the   sky   is    /color/  { # code here }  with  environment  {foo bar}
same  variable           same    same  same  same  variable variable         same     same      variable
when  current-file.folk  wishes  the   sky   is    blue     /lambda/         with  environment  /env/

Note that it doesn't matter if a variable is on top or below, as they're essentially a wildcard.

Our “whenized” statement is now a query that will find all the applicable Whens, as it does in this example.

When scheduling

One exciting thing about folk2 is its support for multithreading. It does this by running each When on its own thread. That means that when a When matches with a Statement, it needs to be queued for the next available thread to pick it up. That's exactly what happened in this example. The Wish got inserted, it checked for matching Whens, and then when it found a match, it pushed it to the work queue to be run as soon as a thread is available.

notes/internals/db.1757203565.txt.gz · Last modified: 2025/09/07 00:06 by smj-edison

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki