Update of /cvsroot/monetdb/pathfinder/runtime
In directory sc8-pr-cvs7.sourceforge.net:/tmp/cvs-serv25104/runtime
Modified Files:
pathfinder.mx pf_support.mx
Log Message:
- finishing the value indexing => they now get maintained under XUF updates
- fixed bugs in te updating code (these got new atr/text values from
PROP_VAL/PROP_TEXT, where they are only found if those values already existed.
if not, we need to check PROP_VAL_UPDATE/PROP_TEXT_UPDATE.
- as it turned out expensive to figure out for changed text nodes which node
was the parent, we went for the asy solution and changed the semantics.
Now text node indexing no longer takes into account the parent element
(ie no condition on its qname). thus, the signature of pf:text() is now:
pf:text($ctx as node()*, $val as xs:string) as text()*
Index: pathfinder.mx
===================================================================
RCS file: /cvsroot/monetdb/pathfinder/runtime/pathfinder.mx,v
retrieving revision 1.316
retrieving revision 1.317
diff -u -d -r1.316 -r1.317
--- pathfinder.mx 4 Apr 2007 09:50:02 -0000 1.316
+++ pathfinder.mx 4 Apr 2007 22:23:56 -0000 1.317
@@ -1880,60 +1880,61 @@
var nme := str(lng(coll_oid)) + "_qn_nid";
var vx_nme := str(lng(coll_oid)) + "_vx_hsh_nid";
if (not(updatable)) {
- var b, err := CATCH(b := reverse(reverse(bat(nme)))); # hack:
reverse/reverse to ensure it gets loaded
+ # hack: reverse/reverse to ensure it gets loaded
+ var b, err := CATCH(b := reverse(reverse(bat(nme))));
if (isnil(err)) return
new(void,bat).insert(nil,b).insert(nil,reverse(reverse(bat(vx_nme))));
}
- # Restrict to new attributes only. The new attributes are >att and have an
attr_own > pre
- var tmp := attr_own.reverse().ord_select(att,oid_nil).reverse();
- if (updatable) # filter nils, created by deletes, from both nid_rid *and*
attr_own
- tmp :=
tmp.leftjoin(rid).ord_select(oid_nil,oid_nil).[swizzle](map_pid);
- tmp := tmp.ord_uselect(pre,oid_nil).hmark([EMAIL PROTECTED]);
- attr_own:= tmp.leftfetchjoin(attr_own);
- attr_qn := tmp.leftfetchjoin(attr_qn);
- attr_prp:= tmp.leftfetchjoin(attr_prp);
-
# compute the nsloc index bat for all nodes > pre (ie the newly shredded
nodes)
- tmp :=
knd.reverse().ord_select(pre,oid_nil).reverse().ord_uselect(ELEMENT).mirror();
- var idx := tmp.leftfetchjoin(prp); # get [pre,qn], in
pre-order
+ var tmp :=
knd.reverse().ord_select(pre,oid_nil).reverse().ord_uselect(ELEMENT).mirror();
+ var idx := tmp.leftfetchjoin(prp); tmp := nil; # get [pre,qn], in
pre-order
idx := reverse(idx.leftjoin(reverse(unq).mirror())); # get [qn,pre],
in pre-order
idx := idx.leftfetchjoin(nid); # [qn,nid] still in
pre-order
- # text/attr indexing, starting with text values (again only for new pre-s
and attr-s)
- tmp := tmp.hmark([EMAIL PROTECTED]);
- # pass the pre elem id as iter id, then we get [elem,text] pre
results
- var vxm := ll_child(tmp, tmp, sze, knd, false, false, min(tmp), max(tmp),
false, TEXT);
- var vxt := vxm.tmark([EMAIL PROTECTED]).leftfetchjoin(prp); # prop_txt
- var vxp := vxm.hmark([EMAIL PROTECTED]); # parent-pre
(i.e. element)
- vxm := [int](vxp.leftfetchjoin(prp)).access(BAT_WRITE);
- vxt := [:rotate_xor_hash=](vxm, 27, vxt.leftfetchjoin(prp_txt));
- vxp := vxp.leftfetchjoin(nid).access(BAT_APPEND);
- # attribute indexing
- tmp := [int](attr_qn).copy().access(BAT_WRITE);
- tmp := [:rotate_xor_hash=](tmp, 27, attr_prp.leftfetchjoin(prp_val));
- # finish index by union and sort
- vxm := reverse(vxt.append(tmp)).leftfetchjoin(vxp.append(attr_own));
- vxm := vxm.access(BAT_WRITE).order().access(BAT_READ);
- vxt := vxm.hmark([EMAIL PROTECTED]);
- vxp := vxm.tmark([EMAIL PROTECTED]);
-
- # filter out highly repeated hsh values from the hsh_nid index (they get
represented just once as [hsh,nil])
+ # compute the text/attr index, starting with text values
+ var vxm :=
knd.reverse().ord_select(pre,oid_nil).reverse().ord_uselect(TEXT).hmark([EMAIL
PROTECTED]);
+ var vxp := vxm.leftfetchjoin(nid).access(BAT_APPEND);
+ var vxt := vxm.leftfetchjoin(prp); vxm := nil;
+ vxt := vxt.leftfetchjoin(prp_txt);
+ vxt := [hash](vxt).access(BAT_APPEND);
+
+ # filter out highly repeated text values from the hsh_nid index
var lim := log2(lng(count(vxt)));
- tmp := [<](histogram(vxt), lim*lim);
+ vxm := histogram(vxt);
+ tmp := [<](vxm, lim*lim);
tmp := vxt.leftjoin(tmp).tmark([EMAIL PROTECTED]).access(BAT_WRITE); #
true for infrequent values
vxp := [ifthenelse](tmp, vxp, oid_nil); # key for infrequent,
nil for infrequent
- vxm := reverse(kunique(reverse(vxt))).project(true);
- tmp := tmp.inplace(vxm).uselect(true).hmark([EMAIL PROTECTED]); #
select first hsh occurrence anyway
- vxm :=
reverse(tmp.leftfetchjoin(vxt)).leftfetchjoin(tmp.leftfetchjoin(vxp));
+ vxm := kunique(reverse(vxt));
+ vxm := reverse(vxm).project(true);
+ tmp := tmp.inplace(vxm).uselect(true).hmark([EMAIL PROTECTED]); vxm :=
nil; # select first hsh occurrence anyway
+ vxt := tmp.leftfetchjoin(vxt);
+ vxp := tmp.leftfetchjoin(vxp); tmp := nil;
- if (updatable) { # hash-index, created here each tiume document is first
used
+ # add the newly shredded attributes. The new attributes are >att and have
an attr_own > pre
+ tmp := attr_own.reverse().ord_select(att,oid_nil).reverse();
+ if (updatable) {
+ # get pre-s from nids, but beware nils in attr_own and pre_nid (left
by deletes)
+ tmp := tmp.leftjoin(rid);
+ tmp := tmp.ord_select(oid_nil,oid_nil);
+ tmp := tmp.[swizzle](map_pid);
+ }
+ tmp := tmp.ord_uselect(pre,oid_nil).hmark([EMAIL PROTECTED]);
+ vxm := [int](tmp.leftfetchjoin(attr_qn)).access(BAT_WRITE);
+ vxm := [:rotate_xor_hash=](vxm, 27,
tmp.leftfetchjoin(attr_prp).leftfetchjoin(prp_val));
+
+ # combine text/attribute index
+ vxt := vxt.access(BAT_APPEND).append(vxm); vxm := nil;
+ tmp := tmp.leftfetchjoin(attr_own);
+ vxp := vxp.access(BAT_APPEND).append(tmp); tmp := nil;
+ vxm := reverse(vxt).leftfetchjoin(vxp); vxp := nil; vxt := nil;
+
+ if (updatable) { # hash-index, created here each time document is first
used
(idx := bat(oid, oid, (count(idx)*4)/3).insert(idx)).accbuild("hash");
(vxm := bat(int, oid, (count(vxm)*4)/3).insert(vxm)).accbuild("hash");
- } else {
- # read-only case creates a persistenly sorted index (uses binary
search)
- idx := idx.ssort().access(BAT_READ); # [qn,pre]
lexico-ordered (thanks to stable-sort)
- idx.rename(nme).mmap(1).persists(true);
- vxm.rename(vx_nme).mmap(1).persists(true);
+ } else { # read-only case. indices are sorted (binary search) and
persistent
+ # idx [qn,pre] lexico-ordered (thanks to stable-sort)
+ idx :=
idx.access(BAT_WRITE).sorder().access(BAT_READ).rename(nme).mmap(1).persists(true);
+ vxm :=
vxm.access(BAT_WRITE).order().access(BAT_READ).rename(vx_nme).mmap(1).persists(true);
if (pre = [EMAIL PROTECTED])
CATCH(pf_checkpoint(bat(void,str).append(nme).append(vx_nme))); # immediate
commit
}
return new(void,bat).insert(nil,idx).insert(nil,vxm);
@@ -2004,7 +2005,7 @@
ins.insert(ins_qn_nid);
del.insert(del_qn_nid);
vxi.insert(ins_vx);
- vxi.insert(del_vx);
+ vxd.insert(del_vx);
}
# store the new size in the UNQ seqbase
var totsize := batsize(idx) + batsize(ins) + batsize(del) +
@@ -2175,7 +2176,7 @@
}
# loop-lifted (attr/text) key lookup, with iteration dependent 'val': thus can
also power joins!
-PROC vx_lookup_cont(BAT[void,bat] ws, oid cont, BAT[void,str] iter_val, str
uri, str loc, bit gettext) : BAT[oid,oid]
+PROC vx_lookup_cont(BAT[void,bat] ws, oid cont, BAT[void,str] iter_val, str
uri, str loc) : BAT[oid,oid]
{
var runtime := ws.fetch(CONT_RUNTIME).fetch(cont);
var coll_shortlock := reverse(runtime).fetch(RT_LOCK_FREELIST);
@@ -2192,11 +2193,15 @@
var vx_hsh_nid_del := ws.fetch(VX_HSH_NID_DEL).fetch(cont);
var map_pid := ws.fetch(MAP_PID).fetch(cont);
var use_index := (cont != WS);
+ var gettext := false;
var iter_cand;
var qns;
# lookup whether we know uri:loc in this collection
- if (isnil(uri)) { # ID access: get any qname that is marked as ID
+ if (isnil(uri) and isnil(loc)) {
+ gettext := true; # text lookup
+ qns := reverse(bat(void,int).append(0)); # matches single dummy qn
+ } else if (isnil(uri)) { # ID access: get any qname that is marked as ID
qns :=
ws.fetch(QN_PREFIX_URI_LOC).fetch(cont).[endsWith](NS_ACCEL_SEP+"id"+NS_ACCEL_SEP).uselect(true);
} else if (isnil(loc)) { # IDREF access: get any qname that is marked as
IDREF
qns :=
ws.fetch(QN_PREFIX_URI_LOC).fetch(cont).[endsWith](NS_ACCEL_SEP+"idref"+NS_ACCEL_SEP).uselect(true);
@@ -2230,8 +2235,11 @@
# avoid doing this when ins/del are empty: res maybe a view on idx
(readonly case)
iter_cand.access(BAT_WRITE).insert(iter_ins).deleteBuns(iter_del).access(BAT_READ);
}
- # check against finding nil NIDs. This means the value was too
frequent and omitted from the index
- if (isnil(min(iter_cand))) use_index := false;
+ # check against finding nil NIDs. These indicate attribute values
ommitted from the index
+ if (isnil(min(iter_cand))) {
+ if (gettext) iter_cand := iter_cand.ord_select(oid_nil,oid_nil);
+ else use_index := false; # was omitted, we have to scan
+ }
}
if (not(use_index)) { # everything is a candidate
iter_cand := cross(iter_val,reverse(pre_kind));
@@ -2241,41 +2249,14 @@
if (gettext) {
# convert the nids into pre-s and sort them
var my_iter := iter_cand.hmark([EMAIL PROTECTED]);
- var my_pre := iter_cand.tmark([EMAIL
PROTECTED]).leftjoin(nid_rid).ord_select(oid_nil,oid_nil).[swizzle](map_pid).tsort();
- my_iter := my_pre.hmark([EMAIL
PROTECTED]).leftfetchjoin(my_iter); # my_iter and my_pre synced
- my_pre := my_pre.tmark([EMAIL PROTECTED]);
-
- # filter out false hits on qname
- var tmp :=
my_pre.leftfetchjoin(pre_prop).leftjoin(qns).hmark([EMAIL PROTECTED]);
- if (count(tmp) < count(my_pre)) {
- my_iter := tmp.leftfetchjoin(my_iter);
- my_pre := tmp.leftfetchjoin(my_pre);
- }
-
- # for the same iter, we may still have found the same node twice (if
it has two text nodes with the same value)
- tmp := CTrefine(my_pre, my_iter); # ordered duplicate
elimination, to benefit from stored pre-s
- if (max(tmp) < oid(count(my_pre))) {
- tmp := tmp.reverse().kunique().tmark([EMAIL PROTECTED]);
- my_iter := tmp.leftfetchjoin(my_iter);
- my_pre := tmp.leftfetchjoin(my_pre);
- }
-
- # go to text children. TRICK: get [my,child-pre] by passing my as
'iter'. NOTE: duplicate 'my'-s possible
- tmp := [oid](mirror(chk_order(my_pre)));
- var min_iter := min(my_pre);
- var max_iter := max(my_pre);
- var one_iter := min_iter = max_iter;
- var one_item := count(my_pre) = 1;
- tmp := ll_child(tmp, my_pre, pre_size, pre_kind, one_iter,
one_item, min_iter, max_iter, false, TEXT);
- var chk_my := tmp.hmark([EMAIL PROTECTED]);
- var chk_child := tmp.tmark([EMAIL PROTECTED]);
+ var tmp := iter_cand.tmark([EMAIL
PROTECTED]).leftfetchjoin(nid_rid).[swizzle](map_pid).tsort();
+ my_iter := tmp.hmark([EMAIL PROTECTED]).leftfetchjoin(my_iter);
# my_iter and my_pre synced
+ var my_pre := tmp.tmark([EMAIL PROTECTED]);
{ # check whether string value actually matches something in 'iter_val'
- var chk_text :=
chk_child.leftfetchjoin(pre_prop).leftfetchjoin(prop_text);
- var chk_val :=
chk_my.leftfetchjoin(my_iter).leftjoin(iter_val).tmark([EMAIL PROTECTED]);
- tmp := [=](chk_val, chk_text).ord_uselect(true); }
- # if a node has two equal children, we again got
duplicate my's here => elim with tunique()
- tmp := chk_order(tmp.hmark([EMAIL
PROTECTED]).leftfetchjoin(chk_my)).tunique();
+ var my_text :=
my_pre.leftfetchjoin(pre_prop).leftfetchjoin(prop_text);
+ var my_val := my_iter.leftfetchjoin(iter_val).tmark([EMAIL
PROTECTED]);
+ tmp := [=](my_val, my_text).ord_uselect(true); }
iter_cand :=
reverse(mirror(tmp).leftfetchjoin(my_iter)).leftfetchjoin(my_pre);
} else {
# attribute lookup, use get_attr_own to get the attr-ids of the nids
in iter_cand
@@ -2291,7 +2272,6 @@
chk_attr := tmp.leftfetchjoin(chk_attr);
chk_my := tmp.leftfetchjoin(chk_my);
}
-
{ # check whether string value actually matches something in 'iter_val'
var chk_text :=
chk_attr.leftfetchjoin(attr_prop).leftfetchjoin(prop_val);
var chk_val :=
chk_my.leftfetchjoin(my_iter).leftjoin(iter_val).tmark([EMAIL PROTECTED]);
@@ -2305,14 +2285,14 @@
bat[void,oid] id_iter,
bat[void,int] id_kind,
bat[void,str] iter_val,
- str uri, str loc, bit gettext) : BAT[oid,oid]
+ str uri, str loc) : BAT[oid,oid]
{
- var id_pre := bat(oid,oid,10000);
+ var id_pre := bat(oid,oid,10000);
var id_cont := get_container(id_kind);
id_cont.tunique().sort()@batloop() {
var key_val := id_cont.ord_uselect($h).hmark([EMAIL
PROTECTED]).leftfetchjoin(id_iter).leftfetchjoin(iter_val.tmark([EMAIL
PROTECTED]));
- var key_pre := vx_lookup_cont(ws, $h, key_val, uri, loc, gettext);
+ var key_pre := vx_lookup_cont(ws, $h, key_val, uri, loc);
id_pre.insert(key_pre);
}
return id_pre; # sorted on pre
@@ -2364,11 +2344,11 @@
var split_rootpre :=
split.leftfetchjoin(split_root).leftfetchjoin(nid_rid).[swizzle](map_pid);
# use vx_lookup() to get the element nodes holding any ID/IDREF
attribute
- var id__val := id_split.leftjoin(split_tokens);
+ var id_pre;
+ { var id__val := id_split.leftjoin(split_tokens);
var key_val := id__val.tmark([EMAIL PROTECTED]);
var key_id := id__val.hmark([EMAIL PROTECTED]);
- var key_pre := vx_lookup_cont(ws, cont, key_val, uri, loc, false);
- var id_pre;
+ var key_pre := vx_lookup_cont(ws, cont, key_val, uri, loc);
if (isid) { # for ID() we also perform NID access; merging with IDs,
conserves pre-order
id_pre :=
id_split.leftjoin(split_nids).leftjoin(nid_rid).[swizzle](map_pid).tsort();
@@ -2377,7 +2357,7 @@
key_pre := id_pre.fetch(0);
key_id := id_pre.fetch(1);
}
- id_pre := reverse(key_id).leftfetchjoin(key_pre);
+ id_pre := reverse(key_id).leftfetchjoin(key_pre); }
# for all specified document roots in this container (ONLY!), insert
the found results
split_rootpre.tsort().tunique()@batloop() {
@@ -2552,12 +2532,17 @@
}
# helper to compute [hsh,nid] combinations for the VX index
-PROC vx_maintain(BAT[oid,oid] parent,
+PROC vx_maintain(BAT[oid,oid] nid,
BAT[oid,oid] qn,
BAT[oid,str] val) : BAT[int,oid]
{
- var hsh := [:rotate_xor_hash=]([int](qn).access(BAT_WRITE), 27, val);
- return reverse(hsh).leftfetchjoin(parent);
+ return reverse([:rotate_xor_hash=]([int](qn).access(BAT_WRITE), 27,
val)).leftfetchjoin(nid);
+}
+
+PROC vx_maintain(BAT[oid,oid] nid,
+ BAT[oid,str] val) : BAT[int,oid]
+{
+ return reverse([hash](val)).leftfetchjoin(nid);
}
Index: pf_support.mx
===================================================================
RCS file: /cvsroot/monetdb/pathfinder/runtime/pf_support.mx,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- pf_support.mx 4 Apr 2007 10:44:37 -0000 1.204
+++ pf_support.mx 4 Apr 2007 22:23:56 -0000 1.205
@@ -2585,7 +2585,9 @@
# only keep attributes that are set to new values (i.e. not deleted)
attr_prop_update := attr_prop_update.ord_select(oid_nil,
oid_nil).sort(); # [ATID,PROP]
var map_new_old := attr_prop_update.hmark([EMAIL PROTECTED]); # [i,ATID]
- var newval := attr_prop_update.tmark([EMAIL
PROTECTED]).leftfetchjoin(ws.fetch(PROP_VAL).find(cont)); # [i,str]
+ var newval :=
attr_prop_update.leftjoin(ws.fetch(PROP_VAL).find(cont)).access(BAT_WRITE); #
[i,str]
+
newval.insert(attr_prop_update.leftjoin(ws.fetch(PROP_VAL_UPDATE).find(cont))).order().tmark([EMAIL
PROTECTED]);
+
var newqn :=
map_new_old.join(ws.fetch(ATTR_QN).find(cont)).copy().access(BAT_WRITE).key(true).myupdate(map_new_old.join(ws.fetch(ATTR_QN_UPDATE).find(cont))).order();
# [i,QNID]
var newown :=
map_new_old.join(ws.fetch(ATTR_OWN).find(cont)).copy().access(BAT_WRITE).key(true).myupdate(map_new_old.join(ws.fetch(ATTR_OWN_UPDATE).find(cont))).order();
# [i,OWN]
var newvx := vx_maintain(newown, newqn, newval);
@@ -2624,33 +2626,6 @@
}
if (rids.count() > 0) {
var pres := [swizzle](rids, ws.fetch(MAP_PID_UPDATE).find(cont)); #
[i,newPRE]
-# this code (and the code further down) commented out because it is too slow
-# it shows what to do when vx_maintain must be called when the parent NID and
QN should be passed
-# var parpres := [mil_parent](const ws, cont, pres); #
[i,parentNewPRE]
-# var pid_map_update :=
ws.fetch(MAP_PID_UPDATE).find(cont).select(oid_nil,
oid_nil).reverse().sort().tmark([EMAIL PROTECTED]);
-# var parnids;
-# var parqns;
-# {
-# var parrids := [swizzle](parpres, pid_map_update);
-# # figure out where to get new value
-# var isnewpage := [isnil](outerjoin([oid]([>>]([lng](parrids),
REMAP_PAGE_BITS)), map_pid)); # [i,bit]
-# # rid is on new page
-# var a :=
isnewpage.uselect(true).mirror().join(parrids).join(ws.fetch(_RID_NID).find(cont));
-# # rid is on old page and was modified
-# var b :=
isnewpage.uselect(false).mirror().join(parrids).join(ws.fetch(RID_NID_UPDATE).find(cont));
-# # rid is on old page and was unmodified
-# var c :=
isnewpage.uselect(false).kdiff(b).mirror().join(parrids).[swizzle](map_pid).join(ws.fetch(PRE_NID).find(cont));
-# # select text elements and combine
-# parnids :=
a.access(BAT_WRITE).insert(b).insert(c).order().tmark([EMAIL PROTECTED]); #
[i,NID]
-# # rid is on new page
-# a :=
isnewpage.uselect(true).mirror().join(parrids).join(ws.fetch(_RID_PROP).find(cont));
-# # rid is on old page and was modified
-# b :=
isnewpage.uselect(false).mirror().join(parrids).join(ws.fetch(RID_PROP_UPDATE).find(cont));
-# # rid is on old page and was unmodified
-# c :=
isnewpage.uselect(false).kdiff(b).mirror().join(parrids).[swizzle](map_pid).join(ws.fetch(PRE_PROP).find(cont));
-# # select text elements and combine
-# parqns :=
a.access(BAT_WRITE).insert(b).insert(c).order().tmark([EMAIL PROTECTED]); #
[i,QN]
-# }
{
var nid_rid := ws.fetch(NID_RID).find(cont);
var oldnids := nids.leftjoin(nid_rid.uselect(oid_nil,
oid_nil).mirror()); # [i,NID] (old nodes)
@@ -2659,16 +2634,12 @@
var map_new_old := oldtext.hmark([EMAIL PROTECTED]); # [j,i]
oldtext := oldtext.tmark([EMAIL PROTECTED]); # [j,str]
oldnids := oldnids.tmark([EMAIL PROTECTED]);
- var oldvx := vx_maintain(oldnids, oldnids.project(oid_nil), oldtext);
-# var oldparnids :=
map_new_old.leftfetchjoin(oldpres.mirror()).leftfetchjoin(parnids);
-# var oldparqns :=
map_new_old.leftfetchjoin(oldpres.mirror()).leftfetchjoin(parqns);
-# var oldvx := vx_maintain(oldparnids, oldparqns, oldtext);
- old_text.insert(cont, oldvx);
+ old_text.insert(cont, vx_maintain(oldnids, oldtext));
}
- var vals :=
rids.leftjoin(rid_prop_update).leftjoin(ws.fetch(PROP_TEXT).find(cont));
-# var newvx := vx_maintain(parnids, parqns, vals);
- var newvx := vx_maintain(nids, nids.project(oid_nil), vals);
- new_text.insert(cont, newvx);
+ rids := rids.leftjoin(rid_prop_update);
+ var vals :=
rids.leftjoin(ws.fetch(PROP_TEXT).find(cont)).access(BAT_WRITE);
+
vals.insert(rids.leftjoin(ws.fetch(PROP_TEXT_UPDATE).find(cont))).order().tmark([EMAIL
PROTECTED]);
+ new_text.insert(cont, vx_maintain(nids, vals));
} else {
old_text.insert(cont, new(int,oid));
new_text.insert(cont, new(int,oid));
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Monetdb-pf-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-pf-checkins