1 /* This file is part of the Zebra server.
2 Copyright (C) 1995-2008 Index Data
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 static int dict_ins (Dict dict, const Dict_char *str,
32 Dict_ptr back_ptr, int userlen, void *userinfo);
33 static void clean_page (Dict dict, Dict_ptr ptr, void *p, Dict_char *out,
34 Dict_ptr subptr, char *userinfo);
37 static Dict_ptr new_page (Dict dict, Dict_ptr back_ptr, void **pp)
40 Dict_ptr ptr = dict->head.last;
41 if (!dict->head.freelist)
43 dict_bf_newp (dict->dbf, dict->head.last, &p, dict->head.page_size);
48 ptr = dict->head.freelist;
49 dict_bf_readp (dict->dbf, ptr, &p);
50 dict->head.freelist = DICT_backptr(p);
54 DICT_backptr(p) = back_ptr;
56 DICT_size(p) = DICT_infoffset;
57 DICT_bsize(p) = dict->head.page_size;
63 static int split_page (Dict dict, Dict_ptr ptr, void *p)
69 short *indxp, *best_indxp = NULL;
70 Dict_char best_char = 0;
71 Dict_char prev_char = 0;
72 int best_no = -1, no_current = 1;
75 /* determine splitting char... */
76 indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
77 for (i = DICT_nodir (p); --i >= 0; --indxp)
79 if (*indxp > 0) /* tail string here! */
83 memcpy (&dc, (char*) p + *indxp, sizeof(dc));
85 { /* first entry met */
86 best_char = prev_char = dc;
90 else if (prev_char == dc)
91 { /* same char prefix. update */
92 if (++no_current > best_no)
93 { /* best entry so far */
100 { /* new char prefix. restore */
106 assert(best_no >= 0); /* we didn't find any tail string entry at all! */
108 j = best_indxp - (short*) p;
109 subptr = new_page (dict, ptr, &subp);
110 /* scan entries to see if there is a string with */
111 /* length 1. info_here indicates if such entry exist */
113 for (i=0; i<best_no; i++, j++)
119 info = (char*) p + ((short*) p)[j];
121 memcpy (&dc, info, sizeof(dc));
122 assert (dc == best_char);
123 slen = 1+dict_strlen((Dict_char*) info);
129 info_here = info+slen*sizeof(Dict_char);
133 info1 = info+slen*sizeof(Dict_char); /* info start */
134 dict_ins (dict, (Dict_char*) (info+sizeof(Dict_char)),
135 subptr, *info1, info1+1);
136 dict_bf_readp (dict->dbf, ptr, &p);
139 /* now clean the page ... */
140 clean_page (dict, ptr, p, &best_char, subptr, info_here);
144 static void clean_page (Dict dict, Dict_ptr ptr, void *p, Dict_char *out,
145 Dict_ptr subptr, char *userinfo)
147 char *np = (char *) xmalloc (dict->head.page_size);
149 short *indxp1, *indxp2;
152 DICT_bsize(np) = dict->head.page_size;
153 indxp1 = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
154 indxp2 = (short*) ((char*) np+DICT_bsize(np));
155 info2 = (char*) np + DICT_infoffset;
156 for (i = DICT_nodir (p); --i >= 0; --indxp1)
158 if (*indxp1 > 0) /* tail string here! */
160 /* string (Dict_char *) DICT_EOS terminated */
161 /* unsigned char length of information */
162 /* char * information */
164 info1 = (char*) p + *indxp1;
165 if (out && memcmp (out, info1, sizeof(Dict_char)) == 0)
169 *--indxp2 = -(info2 - np);
170 memcpy (info2, &subptr, sizeof(Dict_ptr));
171 info2 += sizeof(Dict_ptr);
172 memcpy (info2, out, sizeof(Dict_char));
173 info2 += sizeof(Dict_char);
176 memcpy (info2, userinfo, *userinfo+1);
177 info2 += *userinfo + 1;
185 *--indxp2 = info2 - np;
186 slen = (dict_strlen((Dict_char*) info1)+1)*sizeof(Dict_char);
187 memcpy (info2, info1, slen);
193 /* Dict_ptr subptr */
194 /* Dict_char sub char */
195 /* unsigned char length of information */
196 /* char * information */
198 assert (*indxp1 < 0);
199 *--indxp2 = -(info2 - np);
200 info1 = (char*) p - *indxp1;
201 memcpy (info2, info1, sizeof(Dict_ptr)+sizeof(Dict_char));
202 info1 += sizeof(Dict_ptr)+sizeof(Dict_char);
203 info2 += sizeof(Dict_ptr)+sizeof(Dict_char);
206 memcpy (info2, info1, slen);
211 memcpy ((char*)p+DICT_infoffset,
212 (char*)np+DICT_infoffset,
213 info2 - ((char*)np+DICT_infoffset));
214 memcpy ((char*)p + ((char*)indxp2 - (char*)np),
216 ((char*) np+DICT_bsize(p)) - (char*)indxp2);
218 memcpy ((char*)p+DICT_infoffset, (char*)np+DICT_infoffset,
219 DICT_pagesize(dict)-DICT_infoffset);
221 DICT_size(p) = info2 - np;
225 dict_bf_touch (dict->dbf, ptr);
230 /* return 0 if new */
231 /* return 1 if before but change of info */
232 /* return 2 if same as before */
234 static int dict_ins (Dict dict, const Dict_char *str,
235 Dict_ptr ptr, int userlen, void *userinfo)
237 int hi, lo, mid, slen, cmp = 1;
242 dict_bf_readp (dict->dbf, ptr, &p);
248 hi = DICT_nodir(p)-1;
249 indxp = (short*) ((char*) p+DICT_bsize(p)-sizeof(short));
255 /* string (Dict_char *) DICT_EOS terminated */
256 /* unsigned char length of information */
257 /* char * information */
258 info = (char*)p + indxp[-mid];
259 cmp = dict_strcmp((Dict_char*) info, str);
262 info += (dict_strlen((Dict_char*) info)+1)*sizeof(Dict_char);
263 /* consider change of userinfo length... */
264 if (*info == userlen)
266 /* change of userinfo ? */
267 if (memcmp (info+1, userinfo, userlen))
269 dict_bf_touch (dict->dbf, ptr);
270 memcpy (info+1, userinfo, userlen);
276 else if (*info > userlen)
278 /* room for new userinfo */
281 dict_bf_touch (dict->dbf, ptr);
282 memcpy (info+1, userinfo, userlen);
293 /* Dict_ptr subptr */
294 /* Dict_char sub char */
295 /* unsigned char length of information */
296 /* char * information */
297 info = (char*)p - indxp[-mid];
298 memcpy (&dc, info+sizeof(Dict_ptr), sizeof(Dict_char));
302 memcpy (&subptr, info, sizeof(Dict_ptr));
303 if (*++str == DICT_EOS)
305 /* finish of string. Store userinfo here... */
307 int xlen = info[sizeof(Dict_ptr)+sizeof(Dict_char)];
310 if (memcmp (info+sizeof(Dict_ptr)+sizeof(Dict_char)+1,
313 dict_bf_touch (dict->dbf, ptr);
314 memcpy (info+sizeof(Dict_ptr)+sizeof(Dict_char)+1,
320 else if (xlen > userlen)
323 info[sizeof(Dict_ptr)+sizeof(Dict_char)] = userlen;
324 memcpy (info+sizeof(Dict_ptr)+sizeof(Dict_char)+1,
326 dict_bf_touch (dict->dbf, ptr);
329 /* xlen < userlen, expanding needed ... */
330 if (DICT_size(p)+sizeof(Dict_char)+sizeof(Dict_ptr)+
332 DICT_bsize(p) - (1+DICT_nodir(p))*sizeof(short))
334 /* not enough room - split needed ... */
335 if (DICT_type(p) == 1)
337 clean_page (dict, ptr, p, NULL, 0, NULL);
338 return dict_ins (dict, str-1, ptr,
341 if (split_page (dict, ptr, p))
343 yaz_log (YLOG_FATAL, "Unable to split page %d\n", ptr);
346 return dict_ins (dict, str-1, ptr, userlen, userinfo);
349 { /* enough room - no split needed ... */
350 info = (char*)p + DICT_size(p);
351 memcpy (info, &subptr, sizeof(subptr));
352 memcpy (info+sizeof(Dict_ptr), &dc, sizeof(Dict_char));
353 info[sizeof(Dict_char)+sizeof(Dict_ptr)] = userlen;
354 memcpy (info+sizeof(Dict_char)+sizeof(Dict_ptr)+1,
356 indxp[-mid] = -DICT_size(p);
357 DICT_size(p) += sizeof(Dict_char)+sizeof(Dict_ptr)
360 dict_bf_touch (dict->dbf, ptr);
370 subptr = new_page (dict, ptr, NULL);
371 memcpy (info, &subptr, sizeof(subptr));
372 dict_bf_touch (dict->dbf, ptr);
374 return dict_ins (dict, str, subptr, userlen, userinfo);
384 if (lo>hi && cmp < 0)
386 slen = (dict_strlen(str)+1)*sizeof(Dict_char);
387 if (DICT_size(p)+slen+userlen >=
388 (int)(DICT_bsize(p) - (1+DICT_nodir(p))*sizeof(short)))/* overflow? */
392 clean_page (dict, ptr, p, NULL, 0, NULL);
393 return dict_ins (dict, str, ptr, userlen, userinfo);
395 split_page (dict, ptr, p);
396 return dict_ins (dict, str, ptr, userlen, userinfo);
402 indxp1 = (short*)((char*) p + DICT_bsize(p)
403 - DICT_nodir(p)*sizeof(short));
404 for (; indxp1 != indxp; indxp1++)
405 indxp1[0] = indxp1[1];
407 indxp1 = (short*) ((char*) p+DICT_pagesize(dict)-sizeof(short));
408 for (i = DICT_nodir (p); --i >= 0; --indxp1)
412 info = (char*)p - *indxp1;
413 assert (info[sizeof(Dict_ptr)] > ' ');
420 info = (char*)p + DICT_size(p);
421 memcpy (info, str, slen);
424 memcpy (info, userinfo, userlen);
427 *indxp = DICT_size(p);
428 DICT_size(p) = info- (char*) p;
429 dict_bf_touch (dict->dbf, ptr);
435 int dict_insert (Dict dict, const char *str, int userlen, void *userinfo)
440 if (!dict->head.root)
443 dict->head.root = new_page (dict, 0, &p);
444 if (!dict->head.root)
447 return dict_ins (dict, (const Dict_char *) str, dict->head.root,
454 * indent-tabs-mode: nil
456 * vim: shiftwidth=4 tabstop=8 expandtab