Begin by setting the TDB environment variable to a directory where your attribute files will be stored.
% TDB=/usr/glenda/tea
% 9ls /bin/tdbjoin 1058049198 /bin/tdbjoin
% 9ls /bin/tdbjoin |tea 'desc="temporal database join"' 1058049198 /bin/tdbjoin temporal database join
To view the descriptions of all files in /bin
% 9ls /bin |tea desc 1058049198 /bin/tdbjoin temporal database join
Lets change the description slightly making a new description valid at the current time
% 9ls -e /bin/tdbjoin |tea 'desc="join primitive used by tea"' 1058062608 /bin/tdbjoin join primitive used by tea
% 9ls /bin/tdbjoin |tea desc 1058049198 /bin/tdbjoin temporal database join
% 9ls -e /bin/tdbjoin |tea desc 1058062608 /bin/tdbjoin join primitive used by tea
The attributes are stored in files below the directory pointed to by TDB. New files are created as new attributes are named and values assigned to them.
% ls TDB /usr/glenda/tea/desc
% 9ls /bin/tdbjoin |tea desc+ 1058049198 /bin/tdbjoin temporal database join 1058049198 /bin/tdbjoin join primitive used by tea

Let us view the valid times of the attribute values, that is, the valid times that were assigned when they were inserted.
% 9ls /bin/tdbjoin |tea desc+% 1058049198 /bin/tdbjoin temporal database join 1058062524 /bin/tdbjoin join primitive used by tea
% 9ls -e /bin/tdbjoin |tea 'desc% desc=_' 1058062524 /bin/tdbjoin join primitive used by tea % 9ls /bin/tdbjoin |tea desc+ 1058049198 /bin/tdbjoin temporal database join
Say we want to go back in history before deleting that last entry. Just set the ETT environment variable to a time prior to the deletion. Unset the ETT to return to the present.
% ETT=1058062520 % 9ls -e /bin/tdbjoin |tea desc+ 1058049198 /bin/tdbjoin temporal database join 1058062524 /bin/tdbjoin join primitive used by tea % ETT=()
Let us create a relation between a binary file and it's source directory and let us create descriptions for both files and assign an author.
% 9ls -e /bin/acme |tea 'src="/sys/src/cmd/acme"' 1058063753 /bin/acme /sys/src/cmd/acme % 9ls -de /sys/src/cmd/acme /bin/acme |\ tea 'desc="interactive text windows"' 1058064170 /bin/acme interactive text windows 1058064170 /sys/src/cmd/acme interactive text windows % 9ls -de /sys/src/cmd/acme |tea 'author="rob pike"' 1058064216 /sys/src/cmd/acme rob pike
tea 'desc="interactive text windows" author="rob pike"'.
We can now query on /bin/acme and find it's source and author.
% 9ls -e /bin/acme |tea 'src. author' 1058064442 /sys/src/cmd/acme rob pike
This combination of attributes in the tea command line can be thought of as a pipeline (which is in fact how it is implemented by tea). An attribute and any suffixes filter the input for the next attribute in the line. Each attribute in the line only acts on the triad, the first three values separated by tabs in the input.
To list the values of more than one attribute place a comma between attribute names.
% 9ls -e /bin/acme |tea 'src, desc, author'
The effective valid time (EVT) is the first value in the triad. When data is assigned to an attribute the EVT is used to set the start time for the attribute: the time when it becomes valid. (Internally there is also a transaction time which cannot be controlled by the user.)
What then is the end time?
The end time depends on the interpretation of an attribute, and this interpretation is set by the suffix flags we append to the attribute name in our tea query.
In one of our examples above the second assignment to desc for the /bin/tdbjoin element meant the new value became the effective value. This is the default interpretation: The new value's start time becomes the end time for the last attibute of the same element. This implies a one-to-one relationship between element and attribute values.
A one-to-many can also be implemented by using '+' and '*' flags. But say we want to explicitly set the end time for an element attribute pair. This is done by inserting the same element and attribute values twice but with different valid times. The earlier time is the start and the later time is the end. The validity of the element attribute pair is toggled along the valid time line with each new instance of the pair. Use the '^' symbol as the flag to support the toggle of the valid time line.
% 9ls /club |tea 'members^'
We can also query the valid time line without listing the elements first using 9ls. For example, say we want to see all elements in the desc attribute that were assigned today.
% tea desc:
# All elements in desc % tea desc:, # All elements in the January of the current year % tea desc:0101,0201 # Elements on the 1st of the current month % tea desc:1 # Elements in 2002 % tea desc:20020101,20030101
The attribute files are Btrees. A file contains a header block and a sequence of data blocks each containing an array of entries. The entries are variable length and each block has a rudimentary form of compression, whereby contiguous like keys and values are collapsed. Each entry is stored in 3 inversions with each inversion sorted on time, element, and attribute, respectively.
The comparision algortihm acomp() is taken from Plan9 look.c. The pack and unpack, GBIT, PBIT, and convE2M convM2E routines are all derived from Plan9 source. The implementation of search and insert for the Btree is derived from Sedgewick, Algorithms in C. The hash, growable array and symbol table are taken from The Practice of Programming, Pike and Kernighan. Some of the prinicples of Binary relations and Btrees are from Knuth, The Art of Programming; N.Rishe, Database Design: The Semantic Modeling Approach; Nevathe, Elmasri, Fundamentals of Database Systems. 9ls is taken from Plan9 source of ls.c.
My own contribution is the application of the Time Element Attribute triad, the standard join condition for the temporal joins, and the concepts for the Valid Time line.
Many thanks go to the authors of Plan 9.