2 * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
46 #define SFSTREE_VERSION 0x0100
48 typedef unsigned long Opaque; /* XXX sizeof(Opaque) == sizeof(void *) */
50 #define CHECK_MEMORY(tree) ( ( (tree)->plainmemory ) ? \
51 tlog(TL_CRIT|TL_EXIT, "Tree in plain memory - read only access") : (void)0 )
54 getNodeSize(SFSTree *info, SFSNode *node) {
59 size += info->datasize;
61 size += sizeof(SFSNode*);
66 SFSNodeData *data = node->data;
68 size += sizeof(SFSNodeData) * node->nchar;
69 size += sizeof(SFSNode*) * node->nchild;
71 for(i=0;i<node->nchar;i++)
72 nfound += data[i].isword;
74 size += nfound*info->datasize;
77 return PTRALIGN(size);
80 static __inline__ SFSNode*
81 getChildPointer(SFSTree *info, SFSNodeData *nodedata) {
82 char *p = ((char*)nodedata) + nodedata->child;
84 if ( info->plainmemory )
85 return (SFSNode*) ( ((char*)(info->node)) + *(Opaque*)p );
90 static __inline__ SFSNode*
91 getSkipChildPointer(SFSTree *info, SFSNode *node) {
92 if ( info->plainmemory )
93 return (SFSNode*) ( ((char*)(info->node)) + *(Opaque*)node->data );
95 return *(SFSNode**)( (char*)(node->data) );
98 static SFSNode* enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd);
99 static SFSNode* addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level);
101 #define STRNCMP(p1,p2,n) ( ((n)==1) ? ( *((char*)(p1))==*((char*)(p2)) ) : (strncmp((char*)(p1), (char*)(p2), (n))==0) )
104 SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in) {
105 if ( datasize % sizeof(u_int32_t) )
106 tlog(TL_ALARM|TL_EXIT,"SFSInit_dp: datasize(%d) should be divided by sizeof(u_int32_t)", datasize);
109 info=(SFSTree*)tmalloc(sizeof(SFSTree));
110 memset(info,0,sizeof(SFSTree));
112 info->datasize = datasize;
114 while(in && in->key) {
123 SFSInit_c(SFSTree *info, char **in) {
128 info=(SFSTree*)tmalloc(sizeof(SFSTree));
129 memset(info,0,sizeof(SFSTree));
142 SFSFindData(SFSTree *info, char *word) {
143 SFSNode *node = info->node;
144 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
145 u_int8_t *ptr =(u_int8_t*)word;
147 while( node && *ptr ) {
148 if ( node->isskip ) {
149 if ( STRNCMP(ptr, ((char*)node)+node->dataptr, node->nchar) ) {
151 if ( *ptr=='\0' && node->isword) {
152 return (void*) ( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0) );
153 } else if ( node->haschild ) {
154 node = getSkipChildPointer(info, node);
161 StopLow = node->data;
162 StopHigh = StopLow + node->nchar;
163 while (StopLow < StopHigh) {
164 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
165 if ( StopMiddle->val == *ptr ) {
167 if ( *ptr=='\0' && StopMiddle->isword ) {
168 return (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
169 } else if ( StopMiddle->haschild ) {
170 node = getChildPointer(info, StopMiddle);
175 } else if ( StopMiddle->val < *ptr ) {
176 StopLow = StopMiddle + 1;
178 StopHigh = StopMiddle;
181 if ( StopLow >= StopHigh )
189 freeFSFNode(SFSTree *info, SFSNode *node, void (*freefunc)(void*)) {
192 if ( node->isskip ) {
194 freeFSFNode(info, *(SFSNode**)(node->data), freefunc);
195 if (freefunc && node->isword && info->datasize)
196 (*freefunc)( (void*)( ((char*)(node->data))+ (node->haschild) ? sizeof(SFSNode*) : 0 ) );
198 SFSNodeData *nd = node->data;
199 char *data= ((char*)node) + node->dataptr;
201 for(i=0;i<node->nchar;i++) {
203 freeFSFNode(info, *(SFSNode**)( ((char*)nd) + nd->child ), freefunc);
204 if (freefunc && nd->isword && info->datasize) {
205 (*freefunc)( (void*)data );
206 data+=info->datasize;
216 SFSFree(SFSTree *info, void (*freefunc)(void*)) {
217 SFSNodeStack *s=info->stack;
219 if (info->node && !info->plainmemory) freeFSFNode(info, info->node, freefunc);
220 if (info->buf) tfree(info->buf);
233 makeSkipNode(SFSTree *info, SFSDataIO *io, int level) {
241 len = (io->keylen > 255) ? 255 : io->keylen;
242 size = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize) + len;
243 size = PTRALIGN(size);
245 res = (SFSNode*)tmalloc(size);
251 res->dataptr = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize);
252 memcpy(((char*)res) + res->dataptr, io->key, len);
254 if ( io->keylen > 255 ) {
257 io->key = io->key+len;
258 io->keylen = io->keylen - len;
259 *(SFSNode**)(res->data) = makeSkipNode(info, io, 0);
260 io->key = io->key-len;
261 io->keylen = io->keylen + len;
265 if (info->datasize) {
266 memcpy( res->data, io->data, info->datasize );
277 splitSkipNode(SFSTree *info, SFSNode* node, SFSDataIO *io, int level) {
283 tassert(node->isskip);
287 s1=((char*)node) + node->dataptr;
290 while( s1 - (((char*)node) + node->dataptr) < node->nchar && s2 - io->key < io->keylen && *s1==*s2) {
295 prefixlen = s2 - io->key;
297 if ( prefixlen==0 ) {
298 if ( node->nchar == 1 ) {
299 int flag = EN_VAL | ((node->isword) ? EN_DATA : 0) | ((node->haschild) ? EN_CHLD : 0);
300 res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), flag, &ndata);
301 if ( node->isword ) {
302 if ( info->datasize )
304 ((char*)res) + res->dataptr + info->datasize * ndata->data,
305 ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0),
309 if ( node->haschild )
310 *(SFSNode**)( ((char*)ndata) + ndata->child ) = *(SFSNode**)( node->data );
311 info->totalen -= getNodeSize(info, node);
317 res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), EN_VAL|EN_CHLD, &ndata);
319 size = getNodeSize(info,node);
323 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + 1, node->nchar);
325 size = getNodeSize(info,node);
328 *(SFSNode**)( ((char*)ndata) + ndata->child ) = (SFSNode*)trealloc(node, size);
330 res = addRecord(info, res, io, 0);
331 } else if (prefixlen==io->keylen) {
332 if (prefixlen==node->nchar) {
333 if ( node->isword || info->datasize==0) {
335 memcpy( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNodeData*) : 0),
341 int osize = PTRALIGN(SFSNHRDSZ + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar);
342 int nsize = PTRALIGN(SFSNHRDSZ + info->datasize + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar);
344 info->totalen += nsize - osize;
346 res=(SFSNode*)trealloc(node,nsize);
347 res->dataptr=SFSNHRDSZ + info->datasize + ((res->haschild) ? sizeof(SFSNodeData*) : 0);
349 memmove(((char*)res) + res->dataptr,
350 ((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), res->nchar);
351 memcpy(((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), io->data, info->datasize);
354 int size = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*) + prefixlen;
355 size = PTRALIGN(size);
359 res = (SFSNode*)tmalloc(size);
363 res->nchar = prefixlen;
364 res->dataptr = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*);
365 memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
367 memcpy(((char*)(res->data)) + sizeof(SFSNodeData*), io->data, info->datasize);
368 info->totalen-=getNodeSize(info,node);
369 node->nchar-=prefixlen;
370 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
371 size = getNodeSize(info,node);
373 *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, size);
375 } else if ( prefixlen==node->nchar ) {
376 int size = SFSNHRDSZ + info->datasize + sizeof(SFSNode*) + node->nchar;
377 info->totalen+=sizeof(SFSNode*);
378 res=(SFSNode*)trealloc(node,size);
379 memmove( ((char*)(res->data)) + sizeof(SFSNode*), res->data, info->datasize + res->nchar);
381 res->dataptr+=sizeof(SFSNode*);
382 *(SFSNode**)(res->data) = makeSkipNode(info, io, prefixlen);
384 int size = SFSNHRDSZ + sizeof(SFSNodeData*) + prefixlen;
385 size = PTRALIGN(size);
388 res = (SFSNode*)tmalloc(size);
392 res->nchar = prefixlen;
393 res->dataptr = SFSNHRDSZ + sizeof(SFSNodeData*);
394 memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
396 info->totalen-= getNodeSize(info,node);
397 node->nchar-=prefixlen;
399 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
401 size = getNodeSize(info,node);
402 info->totalen+= size;
404 *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, size);
405 *(SFSNode**)(res->data) = splitSkipNode(info, *(SFSNode**)(res->data), io, prefixlen);
415 enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd) {
416 u_int32_t nchild=0, nchar=0, nfound=0, i;
428 for(i=0;i<nchar;i++) {
429 nfound += data->isword;
435 /*info->totalen -= PTRALIGN(SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize);*/
436 info->totalen -= getNodeSize(info, node);
438 if ( flag & EN_VAL ) nchar++;
439 if ( flag & EN_CHLD ) nchild++;
440 if ( flag & EN_DATA ) nfound++;
443 sizenode = SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize;
444 sizenode = PTRALIGN(sizenode);
446 info->totalen+=sizenode;
447 if ( !node ) info->nnodes++;
448 rs=(SFSNode*)tmalloc(sizenode);
453 rs->dataptr=SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*);
454 dataptr=((char*)rs) + rs->dataptr;
455 chld = (SFSNode**)( ((char*)rs)+SFSNHRDSZ+nchar*sizeof(SFSNodeData) );
459 SFSNode **ochld=(SFSNode**)( ((char*)node)+SFSNHRDSZ+node->nchar*sizeof(SFSNodeData) );
460 SFSNodeData *odata = node->data;
461 char *odataptr=((char*)node) + node->dataptr;
464 for(i=0;i<node->nchar;i++) {
465 if ( val > odata->val ) {
466 *(u_int32_t*)data = *(u_int32_t*)odata;
467 if ( odata->haschild ) {
469 data->child = ((char*)chld) - ((char*)data);
472 if ( odata->isword && info->datasize ) {
473 memcpy(dataptr, odataptr, info->datasize);
474 data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
475 dataptr += info->datasize; odataptr += info->datasize;
478 } else if ( val == odata->val ) {
479 tassert ( (flag&EN_VAL)==0 );
480 *(u_int32_t*)data = *(u_int32_t*)odata;
482 if ( odata->haschild || flag & EN_CHLD ) {
483 if (odata->haschild) *chld=*ochld;
484 data->child = ((char*)chld) - ((char*)data);
486 chld++; if (odata->haschild) ochld++;
489 if ( odata->isword || flag & EN_DATA ) {
491 if ( info->datasize && odata->isword ) {
492 memcpy(dataptr, odataptr, info->datasize);
493 odataptr += info->datasize;
495 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
496 dataptr += info->datasize;
503 tassert ( flag&EN_VAL );
505 if ( flag & EN_CHLD ) {
507 data->child = ((char*)chld) - ((char*)data);
511 if ( flag & EN_DATA ) {
513 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
514 dataptr += info->datasize;
522 *(u_int32_t*)data = *(u_int32_t*)odata;
523 if ( odata->haschild ) {
525 data->child = ((char*)chld) - ((char*)data);
528 if ( odata->isword && info->datasize ) {
529 memcpy(dataptr, odataptr, info->datasize);
530 data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
531 dataptr += info->datasize; odataptr += info->datasize;
538 tassert ( flag&EN_VAL );
540 if ( flag & EN_CHLD ) {
542 data->child = ((char*)chld) - ((char*)data);
546 if ( flag & EN_DATA ) {
548 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
549 dataptr += info->datasize;
555 tassert ( flag & EN_VAL );
557 if ( flag & EN_CHLD ) {
559 data->child = ((char*)chld) - ((char*)data);
562 if ( flag & EN_DATA ) {
564 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
569 if (node) tfree(node);
574 addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level) {
575 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
576 u_int8_t *ptr = ((u_int8_t*)in->key) + level;
579 if ( node->isskip ) {
580 if ( node->haschild && in->keylen-level > node->nchar &&
581 strncmp(in->key+level, ((char*)node)+node->dataptr, node->nchar)==0 )
582 *(SFSNode**)( node->data ) = addRecord(info, *(SFSNode**)( node->data ), in, level+node->nchar);
584 node = splitSkipNode(info, node, in, level);
586 StopLow = node->data;
587 StopHigh = StopLow + node->nchar;
588 while (StopLow < StopHigh) {
589 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
590 if ( StopMiddle->val == *ptr ) {
591 if ( *(ptr+1)=='\0' ) {
592 if ( StopMiddle->isword ) {
594 if ( info->datasize )
595 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
596 in->data, info->datasize );
599 if (info->datasize) {
600 node = enlargeNode(info, node, *ptr, EN_DATA, &StopMiddle);
601 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
602 in->data, info->datasize );
604 StopMiddle->isword = 1;
606 } else if ( StopMiddle->haschild ) {
607 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
608 addRecord(info, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), in, level+1);
610 node = enlargeNode(info, node, *ptr, EN_CHLD, &StopMiddle);
611 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
612 makeSkipNode(info, in, level+1);
615 } else if ( StopMiddle->val < *ptr ) {
616 StopLow = StopMiddle + 1;
618 StopHigh = StopMiddle;
621 if ( *(ptr+1)=='\0' ) {
622 node = enlargeNode(info, node, *ptr, EN_VAL|EN_DATA, &StopMiddle);
623 if ( info->datasize )
624 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
625 in->data, info->datasize );
627 node = enlargeNode(info, node, *ptr, EN_VAL|EN_CHLD, &StopMiddle);
628 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
629 makeSkipNode(info, in, level+1);
633 node = makeSkipNode(info, in, level);
640 SFSAdd(SFSTree *info, SFSDataIO *in) {
643 in->keylen=strlen(in->key);
644 info->node = addRecord(info, info->node, in, 0);
648 pushStack(SFSNodeStack *top, SFSNode *node, int level ) {
649 SFSNodeStack *r=(SFSNodeStack*)tmalloc(sizeof(SFSNodeStack));
662 SFSIteratorStart(SFSTree *info) {
665 info->buf = (char*)tmalloc(info->tlen);
667 info->stack = pushStack(NULL, info->node, 0);
672 SFSPrefixIteratorStart(SFSTree *info, char *word) {
673 SFSNode *node = info->node;
674 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
675 u_int8_t *ptr =(u_int8_t*)word;
676 int len,wlen=strlen(word);
678 if ( wlen+1>=info->tlen ) {
680 info->buf = (info->buf) ?
681 (char*)trealloc(info->buf,info->tlen)
683 (char*)tmalloc(info->tlen);
687 while( node && *ptr) {
688 len = wlen - (((char*)ptr)-word);
689 if ( node->isskip ) {
690 if ( STRNCMP(ptr, ((char*)node)+node->dataptr, (len<node->nchar) ? len : node->nchar) ) {
691 if ( len<=node->nchar ) {
692 strcpy(info->buf,word);
693 info->stack = pushStack(NULL, node, ((char*)ptr) - word);
695 } else if ( node->haschild ) {
697 node = getSkipChildPointer(info, node);
704 StopLow = node->data;
705 StopHigh = StopLow + node->nchar;
706 while (StopLow < StopHigh) {
707 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
708 if ( StopMiddle->val == *ptr ) {
709 if ( *(ptr+1)=='\0' ) {
710 len =((char*)ptr)-word+1;
711 strcpy(info->buf,word);
712 if ( StopMiddle->isword ) {
714 info->wdata = (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
716 if ( StopMiddle->haschild )
717 info->stack = pushStack(NULL, getChildPointer( info, StopMiddle ), len);
719 } else if ( StopMiddle->haschild ) {
720 node = getChildPointer( info, StopMiddle );
726 } else if ( StopMiddle->val < *ptr ) {
727 StopLow = StopMiddle + 1;
729 StopHigh = StopMiddle;
732 if ( StopLow >= StopHigh )
740 SFSIterate(SFSTree *info, SFSDataIO *out) {
741 SFSNodeStack *s=info->stack;
743 if ( info->hasword ) {
744 out->key = info->buf;
745 out->keylen = strlen(out->key);
746 out->data = info->wdata;
751 if ( s == NULL || s->node == NULL)
754 while ( s->level + s->node->nchar + 1 >= info->tlen ) {
756 info->buf = (char*)trealloc(info->buf, info->tlen);
759 if ( s->node->isskip ) {
760 memcpy( info->buf + s->level, ((char*)s->node) + s->node->dataptr, s->node->nchar );
761 if ( s->node->isword && !s->checkedval) {
762 info->buf[ s->level+s->node->nchar ] = '\0';
763 out->key = info->buf;
764 out->keylen = s->level+s->node->nchar;
765 out->data =((char*)(s->node->data)) + ((s->node->haschild) ? sizeof(SFSNode*) : 0);
769 if ( s->node->haschild && !s->checkedchild) {
770 info->stack = pushStack(s, getSkipChildPointer(info, s->node), s->level+s->node->nchar);
772 if ( SFSIterate(info, out) )
776 while( s->data - s->node->data < s->node->nchar ) {
777 info->buf[ s->level ] = (char)s->data->val;
778 if ( s->checkedval==0 && s->data->isword ) {
779 info->buf[ s->level+1 ] = '\0';
780 out->key = info->buf;
781 out->keylen = s->level+1;
782 out->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
786 if ( s->checkedchild==0 && s->data->haschild ) {
787 info->stack = pushStack(s,
788 getChildPointer( info, s->data ), s->level+1);
790 if ( SFSIterate(info, out) )
793 s->checkedval = s->checkedchild = 0;
797 info->stack = s->next;
800 return SFSIterate(info, out);
804 SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l) {
805 SFSNodeStack *s=info->stack;
807 SFSPrefixIteratorStart(info, word);
810 if ( SFSIterate(info, f) ) {
811 SFSNodeStack *sptr = info->stack, *stmp;
812 while( sptr && sptr!=s ) {
819 memcpy(l,f,sizeof(SFSDataIO));
827 while( f->keylen + s->level + 2 >= info->tlen ) {
829 info->buf = (char*)trealloc(info->buf, info->tlen);
833 l->key = info->buf + f->keylen + 1;
834 memcpy(l->key, f->key, f->keylen + 1);
837 while( f->keylen + 1 + s->level + s->node->nchar + 1 >= info->tlen ) {
839 info->buf = (char*)trealloc(info->buf, info->tlen);
841 if ( s->node->isskip ) {
842 memcpy(info->buf + f->keylen + 1 + s->level,
843 ((char*)(s->node))+s->node->dataptr, s->node->nchar);
844 s->level+=s->node->nchar;
845 if (s->node->haschild) {
846 s->node=getSkipChildPointer(info, s->node);
847 } else { /* if (s->node->isword) */
848 info->buf[ f->keylen + 1 + s->level ] = '\0';
849 l->data = (void*)(s->node->data);
850 l->keylen = s->level+1;
854 s->data = s->node->data + s->node->nchar - 1;
855 while( s->data - s->node->data >= 0 ) {
856 info->buf[ f->keylen + 1 + s->level ] = (char)s->data->val;
857 if ( s->data->haschild ) {
858 s->node = getChildPointer( info, s->data );
862 if ( s->data->isword ) {
863 info->buf[ f->keylen + 1 + s->level ] = '\0';
864 l->keylen = s->level+1;
865 l->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
874 l->key = info->buf + f->keylen + 1;
880 typedef struct WorkPlain {
887 plainNode(WorkPlain *wp, SFSNode *node) {
888 int size = getNodeSize(wp->info, node);
889 off_t myoffset = wp->offset;
891 memcpy( wp->node + wp->offset, node, size );
894 tassert( wp->offset <= wp->info->totalen );
896 if ( node->isskip ) {
898 *(Opaque*)(wp->node + myoffset + SFSNHRDSZ) =
899 plainNode(wp, getSkipChildPointer(wp->info, node));
901 SFSNodeData *nd = node->data;
904 for(i=0;i<node->nchar;i++) {
906 *(Opaque*)(wp->node + myoffset + ( ((char*)nd) - ((char*)node) ) + nd->child) =
907 plainNode(wp, getChildPointer( wp->info, nd ) );
918 SFSMakePlain(SFSTree *info, void *pointer) {
921 if ( info->plainmemory )
927 wp.node = (char*)pointer;
929 wp.node = (char*)tmalloc(sizeof(char*) * info->totalen);
931 plainNode(&wp, info->node);
932 tassert( wp.offset == info->totalen );
934 info->node = (SFSNode*)wp.node;
935 info->plainmemory = 1;
939 revertNode(SFSTree *info, SFSNode* node) {
940 int size = getNodeSize(info, node);
943 newnode = (SFSNode*)tmalloc( size );
944 memcpy(newnode, node, size);
946 if ( node->isskip ) {
948 *(SFSNode**)( (char*)(newnode->data) ) =
949 revertNode(info, getSkipChildPointer(info, node));
951 SFSNodeData *nd = node->data;
952 SFSNodeData *nnd = newnode->data;
955 for(i=0;i<node->nchar;i++) {
957 *(SFSNode**) (((char*)nnd) + nnd->child ) =
958 revertNode(info, getChildPointer( info, nd ));
967 SFSRevertPlain(SFSTree *info) {
968 void *pointer = info->node;
970 if (! info->plainmemory )
973 info->node = revertNode(info, info->node);
974 info->plainmemory = 0;
980 writeNode(WorkPlain *wp, int fd, SFSNode *node) {
981 int size = getNodeSize(wp->info, node);
982 SFSNode *wnode = (SFSNode*)tmalloc(size);
983 off_t myoffset = wp->offset;
985 memcpy( wnode, node, size );
988 tassert( wp->offset <= wp->info->totalen );
990 if ( node->isskip ) {
992 *(Opaque*)( ((char*)wnode) + SFSNHRDSZ) =
993 writeNode(wp, fd, getSkipChildPointer(wp->info, node));
995 SFSNodeData *nd = node->data;
998 for(i=0;i<node->nchar;i++) {
1000 *(Opaque*)(((char*)wnode) + ( ((char*)nd) - ((char*)node) ) + nd->child) =
1001 writeNode(wp, fd, getChildPointer( wp->info, nd ) );
1006 if ( lseek(fd, myoffset + SFSTDHSZ, SEEK_SET) < 0 )
1007 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1008 if ( write(fd, wnode, size) != size )
1009 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1017 SFSWriteDump(SFSTree *info, char *filename) {
1019 off_t size = info->totalen + SFSTDHSZ;
1020 SFSTreeDumpHeader dh;
1022 if ( (fd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_EXLOCK, 0666)) < 0 )
1023 tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", strerror(errno));
1025 if ( lseek(fd, size, SEEK_SET) < 0 )
1026 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1028 dh.version = SFSTREE_VERSION;
1029 dh.opaquesize = sizeof(Opaque);
1030 dh.headersize = SFSTDHSZ;
1031 dh.datasize = info->datasize;
1032 dh.totalen = info->totalen;
1033 dh.nnodes = info->nnodes;
1035 if ( lseek(fd, 0, SEEK_SET) < 0 )
1036 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1037 if ( write(fd, &dh, SFSTDHSZ) != SFSTDHSZ )
1038 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1040 if ( info->plainmemory ) {
1041 if ( write(fd, info->node, info->totalen) != info->totalen )
1042 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1049 writeNode(&wp, fd, info->node);
1056 readNode(SFSTree *info, int fd, char *buf, int bufsize) {
1060 size = read(fd, buf, bufsize );
1061 if ( size < SFSNHRDSZ + sizeof(void*) )
1062 tlog(TL_CRIT|TL_EXIT, "read failed: %s", strerror(errno));
1064 size = getNodeSize(info, (SFSNode*)buf);
1065 tassert( size <= bufsize );
1066 node = (SFSNode*)tmalloc( size );
1067 memcpy(node, buf, size);
1069 if ( node->isskip ) {
1070 if (node->haschild) {
1071 if ( lseek(fd, *(Opaque*)node->data + SFSTDHSZ, SEEK_SET) < 0 )
1072 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1073 *(SFSNode**)( (char*)(node->data) ) =
1074 readNode(info, fd, buf, bufsize);
1077 SFSNodeData *nd = node->data;
1080 for(i=0;i<node->nchar;i++) {
1082 if ( lseek(fd, *(Opaque*)(((char*)nd) + nd->child ) + SFSTDHSZ, SEEK_SET) < 0 )
1083 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1084 *(SFSNode**) (((char*)nd) + nd->child ) =
1085 readNode(info, fd, buf, bufsize);
1095 SFSReadDump(SFSTree *info, char *filename) {
1097 SFSTreeDumpHeader dh;
1101 memset(info,0,sizeof(SFSTree));
1103 if ( (fd = open(filename, O_RDONLY|O_SHLOCK)) < 0 )
1104 tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", strerror(errno));
1106 if ( read(fd, &dh, SFSTDHSZ) != SFSTDHSZ )
1107 tlog(TL_CRIT|TL_EXIT, "read failed: %s", strerror(errno));
1109 if ( dh.version != SFSTREE_VERSION )
1110 tlog(TL_CRIT|TL_EXIT, "Tree version mismatch (should be 0x%04x but 0x%04x)", SFSTREE_VERSION, dh.version);
1111 if ( dh.opaquesize != sizeof(Opaque) )
1112 tlog(TL_CRIT|TL_EXIT, "sizeof(Opaque) mismatch");
1113 if ( dh.headersize != SFSTDHSZ )
1114 tlog(TL_CRIT|TL_EXIT, "Tree's header size mismatch (should be %d but %d bytes)", SFSTDHSZ, dh.headersize);
1116 info->totalen = dh.totalen;
1117 info->nnodes = dh.nnodes;
1118 info->datasize = dh.datasize;
1120 /* allocate buffer with max allowed size */
1121 bufsize = SFSNHRDSZ + 256*(sizeof(SFSNodeData) + sizeof(void*) + info->datasize);
1122 buf = tmalloc( bufsize );
1123 info->node = readNode(info, fd, buf, bufsize);
1130 SFSInitFromDump(SFSTree *info, void *pointer, u_int64_t size) {
1131 SFSTreeDumpHeader *dh;
1133 memset(info,0,sizeof(SFSTree));
1135 if ( size && size < SFSTDHSZ )
1136 tlog(TL_CRIT|TL_EXIT, "Memsize too small");
1138 dh = (SFSTreeDumpHeader*)pointer;
1140 if ( dh->version != SFSTREE_VERSION )
1141 tlog(TL_CRIT|TL_EXIT, "Tree version mismatch (should be 0x%04x but 0x%04x)", SFSTREE_VERSION, dh->version);
1142 if ( dh->opaquesize != sizeof(Opaque) )
1143 tlog(TL_CRIT|TL_EXIT, "sizeof(Opaque) mismatch");
1144 if ( dh->headersize != SFSTDHSZ )
1145 tlog(TL_CRIT|TL_EXIT, "Tree's header size mismatch (should be %d but %d bytes)", SFSTDHSZ, dh->headersize);
1146 if ( size && size != dh->totalen + SFSTDHSZ )
1147 tlog(TL_CRIT|TL_EXIT, "Memory size mismatch (should be %d but %d bytes)", dh->totalen + SFSTDHSZ, size);
1149 info->totalen = dh->totalen;
1150 info->nnodes = dh->nnodes;
1151 info->datasize = dh->datasize;
1152 info->plainmemory = 1;
1154 if ( info->totalen && info->nnodes )
1155 info->node = (SFSNode*)( ((char*)pointer) + SFSTDHSZ );