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>
47 #define SFSTREE_VERSION 0x0100
49 typedef unsigned long Opaque; /* XXX sizeof(Opaque) == sizeof(void *) */
51 #define CHECK_MEMORY(tree) ( ( (tree)->plainmemory ) ? \
52 tlog(TL_CRIT|TL_EXIT, "Tree in plain memory - read only access") : (void)0 )
55 getNodeSize(SFSTree *info, SFSNode *node) {
60 size += info->datasize;
62 size += sizeof(SFSNode*);
67 SFSNodeData *data = node->data;
69 size += sizeof(SFSNodeData) * node->nchar;
70 size += sizeof(SFSNode*) * node->nchild;
72 for(i=0;i<node->nchar;i++)
73 nfound += data[i].isword;
75 size += nfound*info->datasize;
78 return PTRALIGN(size);
81 static __inline__ SFSNode*
82 getChildPointer(SFSTree *info, SFSNodeData *nodedata) {
83 char *p = ((char*)nodedata) + nodedata->child;
85 if ( info->plainmemory )
86 return (SFSNode*) ( ((char*)(info->node)) + *(Opaque*)p );
91 static __inline__ SFSNode*
92 getSkipChildPointer(SFSTree *info, SFSNode *node) {
93 if ( info->plainmemory )
94 return (SFSNode*) ( ((char*)(info->node)) + *(Opaque*)node->data );
96 return *(SFSNode**)( (char*)(node->data) );
99 static SFSNode* enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd);
100 static SFSNode* addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level);
102 #define STRNCMP(p1,p2,n) ( ((n)==1) ? ( *((char*)(p1))==*((char*)(p2)) ) : (strncmp((char*)(p1), (char*)(p2), (n))==0) )
105 SFSInit_dp(SFSTree *info, u_int32_t datasize, SFSDataIO *in) {
106 if ( datasize % sizeof(u_int32_t) )
107 tlog(TL_ALARM|TL_EXIT,"SFSInit_dp: datasize(%d) should be divided by sizeof(u_int32_t)", datasize);
110 info=(SFSTree*)tmalloc(sizeof(SFSTree));
111 memset(info,0,sizeof(SFSTree));
113 info->datasize = datasize;
115 while(in && in->key) {
124 SFSInit_c(SFSTree *info, char **in) {
129 info=(SFSTree*)tmalloc(sizeof(SFSTree));
130 memset(info,0,sizeof(SFSTree));
142 #define ISEND(p,w,l) ( (l>0) ? ( ((char*)(p))-(w) < (l) ) : ( *(p) == '\0' ) )
145 SFSFindData(SFSTree *info, char *word, int len) {
146 SFSNode *node = info->node;
147 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
148 u_int8_t *ptr =(u_int8_t*)word;
150 while( node && !ISEND(ptr, word, len) ) {
151 if ( node->isskip ) {
152 if ( len>0 && len - (((char*)ptr) - word) > node->nchar )
154 else if ( STRNCMP(ptr, ((char*)node)+node->dataptr, node->nchar) ) {
156 if ( ISEND(ptr, word, len) && node->isword) {
157 return (void*) ( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0) );
158 } else if ( node->haschild ) {
159 node = getSkipChildPointer(info, node);
166 StopLow = node->data;
167 StopHigh = StopLow + node->nchar;
168 while (StopLow < StopHigh) {
169 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
170 if ( StopMiddle->val == *ptr ) {
172 if ( ISEND(ptr, word, len) && StopMiddle->isword ) {
173 return (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
174 } else if ( StopMiddle->haschild ) {
175 node = getChildPointer(info, StopMiddle);
180 } else if ( StopMiddle->val < *ptr ) {
181 StopLow = StopMiddle + 1;
183 StopHigh = StopMiddle;
186 if ( StopLow >= StopHigh )
194 freeFSFNode(SFSTree *info, SFSNode *node, void (*freefunc)(void*)) {
197 if ( node->isskip ) {
199 freeFSFNode(info, *(SFSNode**)(node->data), freefunc);
200 if (freefunc && node->isword && info->datasize)
201 (*freefunc)( (void*)( ((char*)(node->data))+ (node->haschild) ? sizeof(SFSNode*) : 0 ) );
203 SFSNodeData *nd = node->data;
204 char *data= ((char*)node) + node->dataptr;
206 for(i=0;i<node->nchar;i++) {
208 freeFSFNode(info, *(SFSNode**)( ((char*)nd) + nd->child ), freefunc);
209 if (freefunc && nd->isword && info->datasize) {
210 (*freefunc)( (void*)data );
211 data+=info->datasize;
221 SFSFree(SFSTree *info, void (*freefunc)(void*)) {
222 SFSNodeStack *s=info->stack;
224 if (info->node && !info->plainmemory) freeFSFNode(info, info->node, freefunc);
225 if (info->buf) tfree(info->buf);
238 makeSkipNode(SFSTree *info, SFSDataIO *io, int level) {
246 len = (io->keylen > 255) ? 255 : io->keylen;
247 size = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize) + len;
248 size = PTRALIGN(size);
250 res = (SFSNode*)tmalloc(size);
256 res->dataptr = SFSNHRDSZ + ((io->keylen > 255) ? sizeof(SFSNode*) : info->datasize);
257 memcpy(((char*)res) + res->dataptr, io->key, len);
259 if ( io->keylen > 255 ) {
262 io->key = io->key+len;
263 io->keylen = io->keylen - len;
264 *(SFSNode**)(res->data) = makeSkipNode(info, io, 0);
265 io->key = io->key-len;
266 io->keylen = io->keylen + len;
270 if (info->datasize) {
271 memcpy( res->data, io->data, info->datasize );
282 splitSkipNode(SFSTree *info, SFSNode* node, SFSDataIO *io, int level) {
288 tassert(node->isskip);
292 s1=((char*)node) + node->dataptr;
295 while( s1 - (((char*)node) + node->dataptr) < node->nchar && s2 - io->key < io->keylen && *s1==*s2) {
300 prefixlen = s2 - io->key;
302 if ( prefixlen==0 ) {
303 if ( node->nchar == 1 ) {
304 int flag = EN_VAL | ((node->isword) ? EN_DATA : 0) | ((node->haschild) ? EN_CHLD : 0);
305 res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), flag, &ndata);
306 if ( node->isword ) {
307 if ( info->datasize )
309 ((char*)res) + res->dataptr + info->datasize * ndata->data,
310 ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNode*) : 0),
314 if ( node->haschild )
315 *(SFSNode**)( ((char*)ndata) + ndata->child ) = *(SFSNode**)( node->data );
316 info->totalen -= getNodeSize(info, node);
322 res = enlargeNode(info, NULL, *(u_int8_t*)(((char*)node) + node->dataptr), EN_VAL|EN_CHLD, &ndata);
324 size = getNodeSize(info,node);
328 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + 1, node->nchar);
330 size = getNodeSize(info,node);
333 *(SFSNode**)( ((char*)ndata) + ndata->child ) = (SFSNode*)trealloc(node, size);
335 res = addRecord(info, res, io, 0);
336 } else if (prefixlen==io->keylen) {
337 if (prefixlen==node->nchar) {
338 if ( node->isword || info->datasize==0) {
340 memcpy( ((char*)(node->data)) + ((node->haschild) ? sizeof(SFSNodeData*) : 0),
346 int osize = PTRALIGN(SFSNHRDSZ + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar);
347 int nsize = PTRALIGN(SFSNHRDSZ + info->datasize + ((node->haschild) ? sizeof(SFSNodeData*) : 0) + node->nchar);
349 info->totalen += nsize - osize;
351 res=(SFSNode*)trealloc(node,nsize);
352 res->dataptr=SFSNHRDSZ + info->datasize + ((res->haschild) ? sizeof(SFSNodeData*) : 0);
354 memmove(((char*)res) + res->dataptr,
355 ((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), res->nchar);
356 memcpy(((char*)(res->data)) + ((res->haschild) ? sizeof(SFSNodeData*) : 0), io->data, info->datasize);
359 int size = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*) + prefixlen;
360 size = PTRALIGN(size);
364 res = (SFSNode*)tmalloc(size);
368 res->nchar = prefixlen;
369 res->dataptr = SFSNHRDSZ + info->datasize + sizeof(SFSNodeData*);
370 memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
372 memcpy(((char*)(res->data)) + sizeof(SFSNodeData*), io->data, info->datasize);
373 info->totalen-=getNodeSize(info,node);
374 node->nchar-=prefixlen;
375 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
376 size = getNodeSize(info,node);
378 *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, size);
380 } else if ( prefixlen==node->nchar ) {
381 int size = SFSNHRDSZ + info->datasize + sizeof(SFSNode*) + node->nchar;
382 info->totalen+=sizeof(SFSNode*);
383 res=(SFSNode*)trealloc(node,size);
384 memmove( ((char*)(res->data)) + sizeof(SFSNode*), res->data, info->datasize + res->nchar);
386 res->dataptr+=sizeof(SFSNode*);
387 *(SFSNode**)(res->data) = makeSkipNode(info, io, prefixlen);
389 int size = SFSNHRDSZ + sizeof(SFSNodeData*) + prefixlen;
390 size = PTRALIGN(size);
393 res = (SFSNode*)tmalloc(size);
397 res->nchar = prefixlen;
398 res->dataptr = SFSNHRDSZ + sizeof(SFSNodeData*);
399 memcpy(((char*)res)+res->dataptr, io->key, prefixlen);
401 info->totalen-= getNodeSize(info,node);
402 node->nchar-=prefixlen;
404 memmove( ((char*)node) + node->dataptr, ((char*)node) + node->dataptr + prefixlen, node->nchar);
406 size = getNodeSize(info,node);
407 info->totalen+= size;
409 *(SFSNode**)(res->data) = (SFSNode*)trealloc(node, size);
410 *(SFSNode**)(res->data) = splitSkipNode(info, *(SFSNode**)(res->data), io, prefixlen);
420 enlargeNode(SFSTree *info, SFSNode* node, u_int8_t val, int flag, SFSNodeData **nd) {
421 u_int32_t nchild=0, nchar=0, nfound=0, i;
433 for(i=0;i<nchar;i++) {
434 nfound += data->isword;
440 /*info->totalen -= PTRALIGN(SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize);*/
441 info->totalen -= getNodeSize(info, node);
443 if ( flag & EN_VAL ) nchar++;
444 if ( flag & EN_CHLD ) nchild++;
445 if ( flag & EN_DATA ) nfound++;
448 sizenode = SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*)+nfound*info->datasize;
449 sizenode = PTRALIGN(sizenode);
451 info->totalen+=sizenode;
452 if ( !node ) info->nnodes++;
453 rs=(SFSNode*)tmalloc(sizenode);
458 rs->dataptr=SFSNHRDSZ+nchar*sizeof(SFSNodeData)+nchild*sizeof(SFSNode*);
459 dataptr=((char*)rs) + rs->dataptr;
460 chld = (SFSNode**)( ((char*)rs)+SFSNHRDSZ+nchar*sizeof(SFSNodeData) );
464 SFSNode **ochld=(SFSNode**)( ((char*)node)+SFSNHRDSZ+node->nchar*sizeof(SFSNodeData) );
465 SFSNodeData *odata = node->data;
466 char *odataptr=((char*)node) + node->dataptr;
469 for(i=0;i<node->nchar;i++) {
470 if ( val > odata->val ) {
471 *(u_int32_t*)data = *(u_int32_t*)odata;
472 if ( odata->haschild ) {
474 data->child = ((char*)chld) - ((char*)data);
477 if ( odata->isword && info->datasize ) {
478 memcpy(dataptr, odataptr, info->datasize);
479 data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
480 dataptr += info->datasize; odataptr += info->datasize;
483 } else if ( val == odata->val ) {
484 tassert ( (flag&EN_VAL)==0 );
485 *(u_int32_t*)data = *(u_int32_t*)odata;
487 if ( odata->haschild || flag & EN_CHLD ) {
488 if (odata->haschild) *chld=*ochld;
489 data->child = ((char*)chld) - ((char*)data);
491 chld++; if (odata->haschild) ochld++;
494 if ( odata->isword || flag & EN_DATA ) {
496 if ( info->datasize && odata->isword ) {
497 memcpy(dataptr, odataptr, info->datasize);
498 odataptr += info->datasize;
500 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
501 dataptr += info->datasize;
508 tassert ( flag&EN_VAL );
510 if ( flag & EN_CHLD ) {
512 data->child = ((char*)chld) - ((char*)data);
516 if ( flag & EN_DATA ) {
518 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
519 dataptr += info->datasize;
527 *(u_int32_t*)data = *(u_int32_t*)odata;
528 if ( odata->haschild ) {
530 data->child = ((char*)chld) - ((char*)data);
533 if ( odata->isword && info->datasize ) {
534 memcpy(dataptr, odataptr, info->datasize);
535 data->data = ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize;
536 dataptr += info->datasize; odataptr += info->datasize;
543 tassert ( flag&EN_VAL );
545 if ( flag & EN_CHLD ) {
547 data->child = ((char*)chld) - ((char*)data);
551 if ( flag & EN_DATA ) {
553 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
554 dataptr += info->datasize;
560 tassert ( flag & EN_VAL );
562 if ( flag & EN_CHLD ) {
564 data->child = ((char*)chld) - ((char*)data);
567 if ( flag & EN_DATA ) {
569 data->data = ( info->datasize ) ? ((dataptr - ((char*)rs)) - rs->dataptr)/info->datasize : 0;
574 if (node) tfree(node);
579 addRecord(SFSTree *info, SFSNode* node, SFSDataIO *in, int level) {
580 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
581 u_int8_t *ptr = ((u_int8_t*)in->key) + level;
584 if ( node->isskip ) {
585 if ( node->haschild && in->keylen-level > node->nchar &&
586 strncmp(in->key+level, ((char*)node)+node->dataptr, node->nchar)==0 )
587 *(SFSNode**)( node->data ) = addRecord(info, *(SFSNode**)( node->data ), in, level+node->nchar);
589 node = splitSkipNode(info, node, in, level);
591 StopLow = node->data;
592 StopHigh = StopLow + node->nchar;
593 while (StopLow < StopHigh) {
594 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
595 if ( StopMiddle->val == *ptr ) {
596 if ( *(ptr+1)=='\0' ) {
597 if ( StopMiddle->isword ) {
599 if ( info->datasize )
600 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
601 in->data, info->datasize );
604 if (info->datasize) {
605 node = enlargeNode(info, node, *ptr, EN_DATA, &StopMiddle);
606 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
607 in->data, info->datasize );
609 StopMiddle->isword = 1;
611 } else if ( StopMiddle->haschild ) {
612 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
613 addRecord(info, *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ), in, level+1);
615 node = enlargeNode(info, node, *ptr, EN_CHLD, &StopMiddle);
616 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
617 makeSkipNode(info, in, level+1);
620 } else if ( StopMiddle->val < *ptr ) {
621 StopLow = StopMiddle + 1;
623 StopHigh = StopMiddle;
626 if ( *(ptr+1)=='\0' ) {
627 node = enlargeNode(info, node, *ptr, EN_VAL|EN_DATA, &StopMiddle);
628 if ( info->datasize )
629 memcpy(((char*)node) + node->dataptr + info->datasize * StopMiddle->data,
630 in->data, info->datasize );
632 node = enlargeNode(info, node, *ptr, EN_VAL|EN_CHLD, &StopMiddle);
633 *(SFSNode**)( ((char*)StopMiddle) + StopMiddle->child ) =
634 makeSkipNode(info, in, level+1);
638 node = makeSkipNode(info, in, level);
645 SFSAdd(SFSTree *info, SFSDataIO *in) {
648 in->keylen=strlen(in->key);
649 info->node = addRecord(info, info->node, in, 0);
653 pushStack(SFSNodeStack *top, SFSNode *node, int level ) {
654 SFSNodeStack *r=(SFSNodeStack*)tmalloc(sizeof(SFSNodeStack));
667 SFSIteratorStart(SFSTree *info) {
670 info->buf = (char*)tmalloc(info->tlen);
672 info->stack = pushStack(NULL, info->node, 0);
677 SFSPrefixIteratorStart(SFSTree *info, char *word) {
678 SFSNode *node = info->node;
679 SFSNodeData *StopLow, *StopHigh, *StopMiddle;
680 u_int8_t *ptr =(u_int8_t*)word;
681 int len,wlen=strlen(word);
683 if ( wlen+1>=info->tlen ) {
685 info->buf = (info->buf) ?
686 (char*)trealloc(info->buf,info->tlen)
688 (char*)tmalloc(info->tlen);
692 while( node && *ptr) {
693 len = wlen - (((char*)ptr)-word);
694 if ( node->isskip ) {
695 if ( STRNCMP(ptr, ((char*)node)+node->dataptr, (len<node->nchar) ? len : node->nchar) ) {
696 if ( len<=node->nchar ) {
697 strcpy(info->buf,word);
698 info->stack = pushStack(NULL, node, ((char*)ptr) - word);
700 } else if ( node->haschild ) {
702 node = getSkipChildPointer(info, node);
709 StopLow = node->data;
710 StopHigh = StopLow + node->nchar;
711 while (StopLow < StopHigh) {
712 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
713 if ( StopMiddle->val == *ptr ) {
714 if ( *(ptr+1)=='\0' ) {
715 len =((char*)ptr)-word+1;
716 strcpy(info->buf,word);
717 if ( StopMiddle->isword ) {
719 info->wdata = (void*)( ((char*)node) + node->dataptr + info->datasize * StopMiddle->data );
721 if ( StopMiddle->haschild )
722 info->stack = pushStack(NULL, getChildPointer( info, StopMiddle ), len);
724 } else if ( StopMiddle->haschild ) {
725 node = getChildPointer( info, StopMiddle );
731 } else if ( StopMiddle->val < *ptr ) {
732 StopLow = StopMiddle + 1;
734 StopHigh = StopMiddle;
737 if ( StopLow >= StopHigh )
745 SFSIterate(SFSTree *info, SFSDataIO *out) {
746 SFSNodeStack *s=info->stack;
748 if ( info->hasword ) {
749 out->key = info->buf;
750 out->keylen = strlen(out->key);
751 out->data = info->wdata;
756 if ( s == NULL || s->node == NULL)
759 while ( s->level + s->node->nchar + 1 >= info->tlen ) {
761 info->buf = (char*)trealloc(info->buf, info->tlen);
764 if ( s->node->isskip ) {
765 memcpy( info->buf + s->level, ((char*)s->node) + s->node->dataptr, s->node->nchar );
766 if ( s->node->isword && !s->checkedval) {
767 info->buf[ s->level+s->node->nchar ] = '\0';
768 out->key = info->buf;
769 out->keylen = s->level+s->node->nchar;
770 out->data =((char*)(s->node->data)) + ((s->node->haschild) ? sizeof(SFSNode*) : 0);
774 if ( s->node->haschild && !s->checkedchild) {
775 info->stack = pushStack(s, getSkipChildPointer(info, s->node), s->level+s->node->nchar);
777 if ( SFSIterate(info, out) )
781 while( s->data - s->node->data < s->node->nchar ) {
782 info->buf[ s->level ] = (char)s->data->val;
783 if ( s->checkedval==0 && s->data->isword ) {
784 info->buf[ s->level+1 ] = '\0';
785 out->key = info->buf;
786 out->keylen = s->level+1;
787 out->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
791 if ( s->checkedchild==0 && s->data->haschild ) {
792 info->stack = pushStack(s,
793 getChildPointer( info, s->data ), s->level+1);
795 if ( SFSIterate(info, out) )
798 s->checkedval = s->checkedchild = 0;
802 info->stack = s->next;
805 return SFSIterate(info, out);
809 SFSRange(SFSTree *info, char *word, SFSDataIO *f, SFSDataIO *l) {
810 SFSNodeStack *s=info->stack;
812 SFSPrefixIteratorStart(info, word);
815 if ( SFSIterate(info, f) ) {
816 SFSNodeStack *sptr = info->stack, *stmp;
817 while( sptr && sptr!=s ) {
824 memcpy(l,f,sizeof(SFSDataIO));
832 while( f->keylen + s->level + 2 >= info->tlen ) {
834 info->buf = (char*)trealloc(info->buf, info->tlen);
838 l->key = info->buf + f->keylen + 1;
839 memcpy(l->key, f->key, f->keylen + 1);
842 while( f->keylen + 1 + s->level + s->node->nchar + 1 >= info->tlen ) {
844 info->buf = (char*)trealloc(info->buf, info->tlen);
846 if ( s->node->isskip ) {
847 memcpy(info->buf + f->keylen + 1 + s->level,
848 ((char*)(s->node))+s->node->dataptr, s->node->nchar);
849 s->level+=s->node->nchar;
850 if (s->node->haschild) {
851 s->node=getSkipChildPointer(info, s->node);
852 } else { /* if (s->node->isword) */
853 info->buf[ f->keylen + 1 + s->level ] = '\0';
854 l->data = (void*)(s->node->data);
855 l->keylen = s->level+1;
859 s->data = s->node->data + s->node->nchar - 1;
860 while( s->data - s->node->data >= 0 ) {
861 info->buf[ f->keylen + 1 + s->level ] = (char)s->data->val;
862 if ( s->data->haschild ) {
863 s->node = getChildPointer( info, s->data );
867 if ( s->data->isword ) {
868 info->buf[ f->keylen + 1 + s->level ] = '\0';
869 l->keylen = s->level+1;
870 l->data =((char*)s->node) + s->node->dataptr + info->datasize * s->data->data;
879 l->key = info->buf + f->keylen + 1;
885 typedef struct WorkPlain {
892 plainNode(WorkPlain *wp, SFSNode *node) {
893 int size = getNodeSize(wp->info, node);
894 off_t myoffset = wp->offset;
896 memcpy( wp->node + wp->offset, node, size );
899 tassert( wp->offset <= wp->info->totalen );
901 if ( node->isskip ) {
903 *(Opaque*)(wp->node + myoffset + SFSNHRDSZ) =
904 plainNode(wp, getSkipChildPointer(wp->info, node));
906 SFSNodeData *nd = node->data;
909 for(i=0;i<node->nchar;i++) {
911 *(Opaque*)(wp->node + myoffset + ( ((char*)nd) - ((char*)node) ) + nd->child) =
912 plainNode(wp, getChildPointer( wp->info, nd ) );
923 SFSMakePlain(SFSTree *info, void *pointer) {
926 if ( info->plainmemory )
932 wp.node = (char*)pointer;
934 wp.node = (char*)tmalloc(sizeof(char*) * info->totalen);
936 plainNode(&wp, info->node);
937 tassert( wp.offset == info->totalen );
939 info->node = (SFSNode*)wp.node;
940 info->plainmemory = 1;
944 revertNode(SFSTree *info, SFSNode* node) {
945 int size = getNodeSize(info, node);
948 newnode = (SFSNode*)tmalloc( size );
949 memcpy(newnode, node, size);
951 if ( node->isskip ) {
953 *(SFSNode**)( (char*)(newnode->data) ) =
954 revertNode(info, getSkipChildPointer(info, node));
956 SFSNodeData *nd = node->data;
957 SFSNodeData *nnd = newnode->data;
960 for(i=0;i<node->nchar;i++) {
962 *(SFSNode**) (((char*)nnd) + nnd->child ) =
963 revertNode(info, getChildPointer( info, nd ));
972 SFSRevertPlain(SFSTree *info) {
973 void *pointer = info->node;
975 if (! info->plainmemory )
978 info->node = revertNode(info, info->node);
979 info->plainmemory = 0;
985 writeNode(WorkPlain *wp, int fd, SFSNode *node, u_int32_t extrasize) {
986 int size = getNodeSize(wp->info, node);
987 SFSNode *wnode = (SFSNode*)tmalloc(size);
988 off_t myoffset = wp->offset;
990 memcpy( wnode, node, size );
993 tassert( wp->offset <= wp->info->totalen );
995 if ( node->isskip ) {
997 *(Opaque*)( ((char*)wnode) + SFSNHRDSZ) =
998 writeNode(wp, fd, getSkipChildPointer(wp->info, node), extrasize);
1000 SFSNodeData *nd = node->data;
1003 for(i=0;i<node->nchar;i++) {
1005 *(Opaque*)(((char*)wnode) + ( ((char*)nd) - ((char*)node) ) + nd->child) =
1006 writeNode(wp, fd, getChildPointer( wp->info, nd ), extrasize );
1011 if ( lseek(fd, myoffset + SFSTDHSZ + extrasize, SEEK_SET) < 0 )
1012 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1013 if ( write(fd, wnode, size) != size )
1014 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1022 SFSWriteDump(SFSTree *info, char *filename, void *extradata, u_int32_t extrasize) {
1024 off_t size = info->totalen + SFSTDHSZ;
1025 SFSTreeDumpHeader dh;
1027 if ( (fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0 )
1028 tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", filename, strerror(errno));
1030 if ( flock(fd, LOCK_EX) < 0 )
1031 tlog(TL_CRIT|TL_EXIT, "flock failed: %s", strerror(errno));
1033 if ( extrasize == 0 )
1035 else if ( extradata == NULL )
1038 if ( lseek(fd, size + MAXALIGN(extrasize) , SEEK_SET) < 0 )
1039 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1041 dh.version = SFSTREE_VERSION;
1042 dh.opaquesize = sizeof(Opaque);
1043 dh.headersize = SFSTDHSZ;
1044 dh.datasize = info->datasize;
1045 dh.totalen = info->totalen;
1046 dh.nnodes = info->nnodes;
1047 dh.extrasize = extrasize;
1049 if ( lseek(fd, 0, SEEK_SET) < 0 )
1050 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1051 if ( write(fd, &dh, SFSTDHSZ) != SFSTDHSZ )
1052 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1055 if ( write(fd, extradata, extrasize) != extrasize )
1056 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1057 if ( extrasize != MAXALIGN(extrasize) ) {
1058 char dummy[8] = {0,0,0,0,0,0,0,0};
1059 if ( write(fd, dummy, MAXALIGN(extrasize) - extrasize ) != MAXALIGN(extrasize) - extrasize )
1060 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1062 extrasize = MAXALIGN(extrasize);
1066 if ( info->plainmemory ) {
1067 if ( write(fd, info->node, info->totalen) != info->totalen )
1068 tlog(TL_CRIT|TL_EXIT, "write failed: %s", strerror(errno));
1075 writeNode(&wp, fd, info->node, extrasize);
1083 readNode(SFSTree *info, int fd, char *buf, int bufsize, int extrasize) {
1087 size = read(fd, buf, bufsize );
1088 if ( size < SFSNHRDSZ + sizeof(void*) )
1089 tlog(TL_CRIT|TL_EXIT, "read failed: %s", strerror(errno));
1091 size = getNodeSize(info, (SFSNode*)buf);
1092 tassert( size <= bufsize );
1093 node = (SFSNode*)tmalloc( size );
1094 memcpy(node, buf, size);
1096 if ( node->isskip ) {
1097 if (node->haschild) {
1098 if ( lseek(fd, *(Opaque*)node->data + SFSTDHSZ + extrasize, SEEK_SET) < 0 )
1099 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1100 *(SFSNode**)( (char*)(node->data) ) =
1101 readNode(info, fd, buf, bufsize, extrasize);
1104 SFSNodeData *nd = node->data;
1107 for(i=0;i<node->nchar;i++) {
1109 if ( lseek(fd, *(Opaque*)(((char*)nd) + nd->child ) + SFSTDHSZ + extrasize, SEEK_SET) < 0 )
1110 tlog(TL_CRIT|TL_EXIT, "lseek failed: %s", strerror(errno));
1111 *(SFSNode**) (((char*)nd) + nd->child ) =
1112 readNode(info, fd, buf, bufsize, extrasize);
1122 SFSReadDump(SFSTree *info, char *filename, void **extradata, u_int32_t *extrasize) {
1124 SFSTreeDumpHeader dh;
1133 memset(info,0,sizeof(SFSTree));
1135 if ( (fd = open(filename, O_RDONLY)) < 0 )
1136 tlog(TL_CRIT|TL_EXIT, "Can not open file '%s': %s", strerror(errno));
1137 if ( flock(fd, LOCK_SH) < 0 )
1138 tlog(TL_CRIT|TL_EXIT, "flock failed: %s", strerror(errno));
1140 if ( read(fd, &dh, SFSTDHSZ) != SFSTDHSZ )
1141 tlog(TL_CRIT|TL_EXIT, "read failed: %s", strerror(errno));
1143 if ( dh.version != SFSTREE_VERSION )
1144 tlog(TL_CRIT|TL_EXIT, "Tree version mismatch (should be 0x%04x but 0x%04x)", SFSTREE_VERSION, dh.version);
1145 if ( dh.opaquesize != sizeof(Opaque) )
1146 tlog(TL_CRIT|TL_EXIT, "sizeof(Opaque) mismatch");
1147 if ( dh.headersize != SFSTDHSZ )
1148 tlog(TL_CRIT|TL_EXIT, "Tree's header size mismatch (should be %d but %d bytes)", SFSTDHSZ, dh.headersize);
1150 info->totalen = dh.totalen;
1151 info->nnodes = dh.nnodes;
1152 info->datasize = dh.datasize;
1154 if ( dh.extrasize ) {
1155 void *pointer = tmalloc( MAXALIGN(dh.extrasize) );
1157 if ( read(fd, pointer, MAXALIGN(dh.extrasize)) != MAXALIGN(dh.extrasize) )
1158 tlog(TL_CRIT|TL_EXIT, "read failed: %s", strerror(errno));
1161 *extradata = pointer;
1166 *extrasize = dh.extrasize;
1169 /* allocate buffer with max allowed size */
1170 bufsize = SFSNHRDSZ + 256*(sizeof(SFSNodeData) + sizeof(void*) + info->datasize);
1171 buf = tmalloc( bufsize );
1172 info->node = readNode(info, fd, buf, bufsize, MAXALIGN(dh.extrasize));
1180 SFSInitFromDump(SFSTree *info, void *pointer, u_int64_t size, void **extradata, u_int32_t *extrasize) {
1181 SFSTreeDumpHeader *dh;
1188 memset(info,0,sizeof(SFSTree));
1190 if ( size && size < SFSTDHSZ )
1191 tlog(TL_CRIT|TL_EXIT, "Memsize too small");
1193 dh = (SFSTreeDumpHeader*)pointer;
1195 if ( dh->version != SFSTREE_VERSION )
1196 tlog(TL_CRIT|TL_EXIT, "Tree version mismatch (should be 0x%04x but 0x%04x)", SFSTREE_VERSION, dh->version);
1197 if ( dh->opaquesize != sizeof(Opaque) )
1198 tlog(TL_CRIT|TL_EXIT, "sizeof(Opaque) mismatch");
1199 if ( dh->headersize != SFSTDHSZ )
1200 tlog(TL_CRIT|TL_EXIT, "Tree's header size mismatch (should be %d but %d bytes)", SFSTDHSZ, dh->headersize);
1201 if ( size && size != dh->totalen + SFSTDHSZ + dh->extrasize )
1202 tlog(TL_CRIT|TL_EXIT, "Memory size mismatch (should be %d but %d bytes)", dh->totalen + SFSTDHSZ + dh->extrasize , size);
1204 info->totalen = dh->totalen;
1205 info->nnodes = dh->nnodes;
1206 info->datasize = dh->datasize;
1207 info->plainmemory = 1;
1209 if ( dh->extrasize ) {
1211 *extradata = ((char*)pointer) + SFSTDHSZ;
1214 *extrasize = dh->extrasize;
1217 if ( info->totalen && info->nnodes )
1218 info->node = (SFSNode*)( ((char*)pointer) + SFSTDHSZ + MAXALIGN(dh->extrasize) );