| top | | 39. Node editting ::
Blocks are added by moving portions of one block to another,
or by inserting single items which either strings or block offsets.
Each of the moves starts with a similar pattern
- movewhat(Obj mapping,Word dd,int m,...)
which means to move the new data after dd item,
replacing m (possibly zero or none) items. If m
is less than zero, every following item is replaced. Tail items
after the replaced items are retained, moved into their new position
after the insertion/replacement.
The insertion can be n items form another block (moveblock),
the same block (moveblocko), one item which is a string
(moveobj), or one item which is a block offset
(moveaddr). The reason for various routines suffixed with
-o is given in the next section.
The node block size is continually updated during the editted.
The last routine is used to force the truncation of the overflowed
block back to reasonable size (as well as releasing the overflow).
<Load/store with overflow block checking>
static void blocktail(Obj mapping,Word db,Word dd,int m,Word **tb,Word *tn,OV) {
if (!db) {
Tcl_Panic("[" __FILE__ ":%d] blocktail zero db",__LINE__);
}
if (m>=0) {
while (m-->0) dd = succo(mapping,db,dd,ov);
m = getNodeSizeW(mapping,db)-dd;
if (m<0) Tcl_Panic("[" __FILE__ ":%d] blocktail negative m: db=%d dd=%d size=%d",
__LINE__,db,dd,getNodeSizeW(mapping,db));
*tb = nheap(m,Word); *tn = m;
memcpy(*tb,addro(mapping,db,dd,ov),m*sizeof(Word));
}else {
*tb = 0; *tn = 0;
}
}
static Word repairtail(Obj mapping,Word db,Word dd0,Word *tb,Word tn,OV) {
Word dd = dd0;
if (tn) {
memcpy(addro(mapping,db,dd,ov),tb,tn*sizeof(Word));
dd += tn;
}
dispose(tb);
setNodeSizeW(mapping,db,dd);
if (dd<=getHeaderBlockW(mapping)) refillblock(mapping,db,ov);
return dd0;
}
static void blocksize(Obj mapping,Word db,Word dd,int n,OV) {
if (getNodeSizeW(mapping,db)+n>getHeaderBlockW(mapping)) {
spillblock(mapping,db,ov);
}
}
static Word moveblock(Obj mapping,Word db,Word dd,int m,Word sb,Word ss,int n,OV) {
Word *tb,tn;
if (n>=0) {
Word tt = ss;
while (n-->0) tt = succo(mapping,sb,tt,ov);
n = tt-ss;
}else {
n = getNodeSizeW(mapping,sb)-ss;
}
blocktail(mapping,db,dd,m,&tb,&tn,ov);
blocksize(mapping,db,dd,n,ov);
memmove(addro(mapping,db,dd,ov),addro(mapping,sb,ss,ov),n*sizeof(Word)); dd += n;
return repairtail(mapping,db,dd,tb,tn,ov);
}
static Word moveobj(Intr intr,Obj mapping,Word db,Word dd,int m,Obj ss,long flags,bool key,OV) {
Word *tb,tn,*SS,n; int N; bytes P;
if (key ? (flags&wyrm_assocFlagCompressKey) : (flags&wyrm_assocFlagCompressData)) {
ss = incr(wyrm_huffCompressObj(ss,1,0));
}else
ss = incr(ss);
P = Tcl_GetByteArrayFromObj(ss,&N);
if (N>getHeaderBlock(mapping)/4) {
<Allocate and write out a long string>
n = 2; SS = nheap(n,Word);
SS[0] = htonw((indirectstring<<16) | (flags&0xFFFF));
SS[1] = htonw(longstring);
}else {
n = 2+(N+sizeof(Word)-1)/sizeof(Word); SS = nheap(n,Word);
zero(n,long,SS);
SS[0] = htonw((directstring<<16) | (flags&0xFFFF));
SS[1] = htonw(N);
memcpy(SS+2,P,N);
}
blocktail(mapping,db,dd,m,&tb,&tn,ov);
blocksize(mapping,db,dd,n,ov);
memcpy(addro(mapping,db,dd,ov),SS,n*sizeof(Word)); dd += n;
dispose(SS); decr(ss);
return repairtail(mapping,db,dd,tb,tn,ov);
}
static Word moveaddr(Obj mapping,Word db,Word dd,int m,Word ss,OV) {
Word *tb,tn,SS[2];
SS[0] = htonw(blockoffset<<16);
SS[1] = htonw(ss);
blocktail(mapping,db,dd,m,&tb,&tn,ov);
blocksize(mapping,db,dd,2,ov);
memcpy(addro(mapping,db,dd,ov),SS,2*sizeof(Word)); dd += 2;
return repairtail(mapping,db,dd,tb,tn,ov);
}
static void truncateblock(Obj mapping,Word db,Word dd,OV) {
setNodeSizeW(mapping,db,dd);
refillblock(mapping,db,ov);
}
| ^ | | | | | | section top | |
typedef struct Overflow Overflow;
struct Overflow {
Word block;
Word *buffer;
Overflow *link;
};
#define OV Overflow **ov
#define overflow (*ov)
static void discardspills(OV) {
while (overflow) {
Overflow *t = overflow->link; dispose(overflow->buffer); dispose(overflow); overflow = t;
}
}
static void spillblock(Obj mapping,Word block,OV) {
Overflow *p,*c;
for (p=0,c=overflow; c; p=c,c=c->link) {
if (c->block==block) {
if (p) {p->link = c->link; c->link = overflow; overflow = c;}
return;
}
}
c = heap(Overflow); c->buffer = nheap(3*getHeaderBlockW(mapping),long);
c->block = block; c->link = overflow; overflow = c;
memcpy(c->buffer,addr(mapping,block),getHeaderBlock(mapping));
}
static void refillblock(Obj mapping,Word block,OV) {
Overflow *p,*c;
for (p=0,c=overflow; c; p=c,c=c->link) {
if (c->block==block) {
if (p) p->link = c->link; else overflow = c->link;
memcpy(addr(mapping,block)+2,c->buffer+2,getNodeSize(mapping,block)-2*sizeof(Word));
dispose(c->buffer); dispose(c);
return;
}
}
}
static Word *addro(Obj mapping,Word block,Word off,OV) {
Overflow *p,*c;
for (p=0,c=overflow; c; p=c,c=c->link) {
if (c->block==block) {
if (p) {p->link = c->link; c->link = overflow; overflow = c;}
return c->buffer+off;
}
}
return base(mapping)+block+off;
}
#define loado(mapping,blk,off,ov) (ntohw(*(addro(mapping,blk,off,ov))))
#define storeo(mapping,blk,off,val,ov) ((*(addro(mapping,blk,off,ov))) = htonw(val))
#define getaddro(mapping,blk,item,ov) loado(mapping,blk,item+1,ov)
static Word succo(Obj mapping,Word blk,Word item,OV) {
Word f = loado(mapping,blk,item,ov); item++;
switch ((f>>16)&0xFFFF) {
case directstring: item += (loado(mapping,blk,item,ov)+sizeof(Word)-1)/sizeof(Word);
case blockoffset: case indirectstring: item++; break;
default:
Tcl_Panic("[" __FILE__ ":%d] succo kind unknown: item %d+%d (%d), kind %c, flags %08lx",
__LINE__,blk,item-1,blk+item-1,(f>>16)&0xFFFF,f);
}
return item;
}
| ^ | | | | | | section top | |
Word p,q,r;
if (parent) {
p = 0; q =0; r = nodeheadersizeW;
while (q==0 || getaddro(mapping,parent,q,ov)!=blk) {
p = q; q = r;
r = succo(mapping,parent,r,ov);
if (r>=getNodeSizeW(mapping,parent)) {r = 0; break;}
r = succo(mapping,parent,r,ov);
}
}else
p = q = r = 0;
| ^ | | | | | | section top | | 
if (q && getNodeSize(mapping,blk)<getHeaderBlock(mapping)/4) {
if (r
&& (!p
|| getNodeSize(mapping,getaddro(mapping,parent,succo(mapping,parent,p,ov),ov))
> getNodeSize(mapping,getaddro(mapping,parent,succo(mapping,parent,r,ov),ov))
)
) {
p = q; q = r;
}
if (!p && !r) {
setHeaderRoot(mapping,blk);
freeblock(mapping,blk);
} else {
Word x = getaddro(mapping,parent,p,ov);
Word y = getaddro(mapping,parent,q,ov);
d = moveblock(mapping,x,getNodeSizeW(mapping,x),-1,parent,succo(mapping,parent,p,ov),1,ov);
moveblock(mapping,x,d,-1,y,nodeheadersizeW,-1,ov);
moveblock(mapping,parent,succo(mapping,parent,p,ov),-1,parent,succo(mapping,parent,q,ov),-1,ov);
blk = x; q = p;
freeblock(mapping,y);
}
}
| ^ | | | | | | section top | | 
if (getNodeSize(mapping,blk)>getHeaderBlock(mapping)-nodeheadersize) {
Word m,n,half = getNodeSizeW(mapping,blk)/2;
if (!q) {
parent = newblock(intr,mapping);
if (!parent) return TCL_ERROR;
setHeaderRoot(mapping,parent);
setNodeType(mapping,parent,nodelabel);
setNodeSizeW(mapping,parent,2);
q = nodeheadersizeW; moveaddr(mapping,parent,nodeheadersizeW,0,blk,ov);
}
for (i=nodeheadersizeW; i<half; i=succo(mapping,blk,i,ov)) {
if (i>=getNodeSizeW(mapping,blk)) break;
m = i = succo(mapping,blk,i,ov);
}
n = newblock(intr,mapping);
if (!n) return TCL_ERROR;
setNodeType(mapping,n,node?nodelabel:leaflabel);
setNodeSize(mapping,n,nodeheadersize);
q = moveblock(mapping,parent,succo(mapping,parent,q,ov),0,blk,m,1,ov);
moveaddr(mapping,parent,q,0,n,ov);
moveblock(mapping,n,nodeheadersizeW,-1,blk,succo(mapping,blk,m,ov),-1,ov);
truncateblock(mapping,blk,m,ov);
}
| ^ | | | | | | section top | | 
int cc = K ? strcmp(Tcl_GetString(K),Tcl_GetString(key)) : key ? -1 : 0;
if (put->flags<0) put->flags = F;
if (!key) {
Word B = blockaddr(mapping,d);
Obj D = put->data ? incr(put->data) : getobj(mapping,d,false);
releaseLongstring(mapping,d);
d = blockitem(mapping,d);
d = moveobj(intr,mapping,B,d,1,D,put->flags,false,ov);
decr(D);
if (!d) return TCL_ERROR;
}else if (cc==0) {
Word B = blockaddr(mapping,d);
Obj D = put->data ? incr(put->data) : getobj(mapping,d,false);
bool precedes = succ(mapping,k)==d;
releaseLongstring(mapping,d);
if ((put->flags&wyrm_assocFlagCompressKey)!=(F&wyrm_assocFlagCompressKey)) {
releaseLongstring(mapping,k);
k = moveobj(intr,mapping,blockaddr(mapping,k),blockitem(mapping,k),1,key,put->flags,true,ov);
}else
k = blockitem(mapping,k);
d = precedes ? (k ? succo(mapping,B,k,ov) : 0) : blockitem(mapping,d);
if (k) k = moveobj(intr,mapping,B,d,1,D,put->flags,false,ov);
decr(D);
if (!k) return TCL_ERROR;
}else if (cc>0) {
Word B = blockaddr(mapping,k);
Obj D = put->data ? incr(put->data) : incr(Tcl_NewObj());
k = moveobj(intr,mapping,B,blockitem(mapping,k),0,key,put->flags>=0?put->flags:0,true,ov);
if (k) k = moveobj(intr,mapping,B,k,0,D,put->flags>=0?put->flags:0,false,ov);
decr(D);
if (!k) return TCL_ERROR;
}else if (cc<0) {
Word B = blockaddr(mapping,d);
Obj D = put->data ? incr(put->data) : incr(Tcl_NewObj());
k = moveobj(intr,mapping,B,blockitem(mapping,succ(mapping,d)),0,key,put->flags>=0?put->flags:0,true,ov);
if (k) k = moveobj(intr,mapping,B,k,0,D,put->flags>=0?put->flags:0,false,ov);
decr(D);
if (!k) return TCL_ERROR;
}
| ^ | | | | | | section top | | 
if (!K || !streq(Tcl_GetString(K),Tcl_GetString(key))) {
rprintf(intr,"missing: %{y}s",key);
return TCL_ERROR;
}else if (succ(mapping,k)==d) {
Word kb = blockaddr(mapping,k),ki=blockitem(mapping,k);
releaseLongstring(mapping,k);
releaseLongstring(mapping,d);
if (succ(mapping,d)>=kb+getNodeSizeW(mapping,kb)) {
truncateblock(mapping,kb,ki,ov);
}else {
moveblock(mapping,kb,ki,-1,kb,succo(mapping,kb,succo(mapping,kb,ki,ov),ov),-1,ov);
}
} else {
Word kb = blockaddr(mapping,k),ki=blockitem(mapping,k);
Word db = blockaddr(mapping,d),di=blockitem(mapping,d);
Word nk = succo(mapping,db,di,ov);
releaseLongstring(mapping,k);
releaseLongstring(mapping,d);
moveblock(mapping,kb,ki,1,db,nk,1,ov);
moveblock(mapping,db,di,-1,db,succo(mapping,db,nk,ov),-1,ov);
}
| ^ | | |
| |