1. Varying Tree
A varying tree is a *tree with data at
many different levels. It uses +
to indicate tree structure.
Here is an example:
namespace eval ::myapp {
*tree new mt + {
{ + init "Record initializers" } {
{ + host "Per host/ipaddress statistics"} {
{ badq 0 "Counter for bad queries" }
{ inchars 0 "Total chars received from clients" }
{ lasttime {} "Time of last query" }
{ outchars 0 "Total chars sent to clients" }
{ queries 0 "Counter for queries" }
}
}
{ + status "Global statistics for THS server"} {
{ inchars 0 "Total chars received from clients" -type Int }
{ lastcode {} "Code from last query" -type Int }
{ lasttime {} "Time of last query" }
{ outchars 0 "Total chars sent to clients" }
{ queries 0 "Counter for queries" }
{ + tht "Info for THT" } {
{ queries 0 "Counter of THT queries" -type Int }
{ resident 0 "Counter of Resident THT queries" }
}
{ + bad "Info for last field" } {
{ passwd 0 "Counter for bad password attempts" }
{ qlast {} "HTML from last bad query" }
{ qlasttime {} "Time of last bad query" }
{ queries 0 "Counter for bad queries" }
}
}
{ * hosts "Per host/ipaddress statistics array"} {}
} -typecheck 1
proc UpdCnt {ip cnt} {
# Add some cnt chars for ip. If req create record.
variable mt
if {![$mt exists 0.hosts $ip]} {
$mt set .hosts $ip [$mt get .init.host]
}
$mt incr .hosts ${ip}(inchars) $cnt
}
proc Main {args} {
variable mt
# Update some of the fixed fields
$mt incr .status inchars 3
$mt update .status lasttime -1 queries 4
$mt update .status.tht resident -1 queries 4
$mt update .status.bad passwd 10
# Create and update array fields.
set ini [$mt get .init.host]
$mt set .hosts 192.168.1.101 $ini
$mt set .hosts 192.168.1.102 $ini
$mt incr .hosts 192.168.1.101(inchars)
UpdCnt 192.168.1.104 10
*tree view $mt
*catch { $mt set .status inchars xyz }
*catch { $mt insert .hosts -label 192.168.1.104 }
}
eval Main $argv
}
2. Initialized Data
The data that initializes a varying tree consist of
a sequence of list element where the first element
is one of:
- + : indicates a tree element with sub-trees.
- * : indicates an array element.
- otherwise: indicates a field.
2.1 Field
The first 3 values in a field sequence are:
- the field name
- the field value
- a description
Values may following in name/value pairs,
including -type to provide
type checking.
2.2 Tree
A tree sequence begins with a + and is
followed by the node name. The third (optional)
element is a description.
2.3 Array
We use a * to indicate an array sequence.
This will add the tag _array to the node.
This is used by *tree view to
properly display and edit the data.
In a tree, each key in a node can contain either
an ordinary value or an array. Thus in the above
example we have a single node hosts to which
we add a key for each IP address, and these
each contain an array (somewhat like a dict).
One might wonder why not just insert nodes in host for each IP?
That would certainly work, however, period is a delimiter
in *tree so we could not then use the IP address
as a label, ie. for lookups. (See Validation).
3. Validation
In a non-flat *tree the period is a record
delimiter, so using one in a label will generate an error.
When run with wize -Wall or
when using the -typecheck option, tree will typecheck
accesses to fields which define -type.
If a type doesn't match, an error is raised
and the value is restored. eg.
*catch { $mt set .status inchars xyz }
*catch { $mt insert .hosts -label 192.168.1.104 }
Warn: *catch(1): 'type mismatch: Int xyz: Int' in 'Main'
Evaling: '$mt set .status inchars xyz'
Warn: *catch(1): 'label with dot: 192.168.1.104can't allocate new node' in 'Main'
Evaling: '$mt insert .hosts -label 192.168.1.104'
4. Root
The keys in the root node are used to store the
description (in -cmt) and attributes such as -type
for the fields. This is used for typechecking.
© 2008 Peter MacDonald