OSDN Git Service

Initial commit of senna-1.1.2-fast.
[ludiafuncs/senna-1.1.2-fast.git] / lib / inv.c
1 /* Copyright(C) 2004 Brazil
2
3   This library is free software; you can redistribute it and/or
4   modify it under the terms of the GNU Lesser General Public
5   License as published by the Free Software Foundation; either
6   version 2.1 of the License, or (at your option) any later version.
7
8   This library is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   Lesser General Public License for more details.
12
13   You should have received a copy of the GNU Lesser General Public
14   License along with this library; if not, write to the Free Software
15   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17 #include "senna_in.h"
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <sys/stat.h>
22
23 #include "ctx.h"
24 #include "sym.h"
25 #include "inv.h"
26
27 /* v08 functions */
28
29 void sen_inv_seg_expire08(sen_inv *inv);
30 sen_inv * sen_inv_create08(const char *path,  sen_sym *lexicon,
31                            uint32_t initial_n_segments);
32 sen_inv * sen_inv_open08(const char *path, sen_sym *lexicon);
33 sen_rc sen_inv_update08(sen_inv *inv, uint32_t key, sen_inv_updspec *u, sen_set *h,
34                         int hint);
35 sen_rc sen_inv_delete08(sen_inv *inv, uint32_t key, sen_inv_updspec *u, sen_set *h);
36 sen_inv_cursor *sen_inv_cursor_open08(sen_inv *inv, uint32_t key);
37 sen_rc sen_inv_cursor_next08(sen_inv_cursor *c);
38 sen_rc sen_inv_cursor_next_pos08(sen_inv_cursor *c);
39 sen_rc sen_inv_cursor_close08(sen_inv_cursor *c);
40 uint32_t sen_inv_estimate_size08(sen_inv *inv, uint32_t key);
41 int sen_inv_entry_info08(sen_inv *inv, unsigned key, unsigned *a, unsigned *pocket,
42                          unsigned *chunk, unsigned *chunk_size, unsigned *buffer_free,
43                          unsigned *nterms, unsigned *nterms_void, unsigned *tid,
44                          unsigned *size_in_chunk, unsigned *pos_in_chunk,
45                          unsigned *size_in_buffer, unsigned *pos_in_buffer);
46
47 struct _sen_inv {
48   uint8_t v08p;
49   sen_io *seg;
50   sen_io *chunk;
51   sen_sym *lexicon;
52   struct sen_inv_header *header;
53 };
54
55 struct sen_inv_header {
56   char idstr[16];
57   uint32_t initial_n_segments;
58   uint32_t total_chunk_size;
59   uint32_t amax;
60   uint32_t bmax;
61   uint32_t smax;
62   uint32_t reserved[7];
63   uint16_t ainfo[SEN_INV_MAX_SEGMENT];
64   uint16_t binfo[SEN_INV_MAX_SEGMENT];
65   uint8_t chunks[1]; /* dummy */
66 };
67
68 #define SEN_INV_IDSTR "SENNA:INV:01.00"
69 #define SEN_INV_SEGMENT_SIZE 0x40000
70 #define SEN_INV_CHUNK_SIZE   0x40000
71 #define N_CHUNKS_PER_FILE (SEN_IO_FILE_SIZE / SEN_INV_CHUNK_SIZE)
72 #define W_OF_SEGMENT 18
73 #define W_OF_ARRAY (W_OF_SEGMENT - 2)
74 #define ARRAY_MASK_IN_A_SEGMENT ((SEN_INV_SEGMENT_SIZE >> 2) - 1)
75 #define BUFFER_MASK_IN_A_SEGMENT (SEN_INV_SEGMENT_SIZE - 1)
76 #define CHUNK_NOT_ASSIGNED 0xffffffff
77 #define SEG_NOT_ASSIGNED 0xffff
78
79 #define SEGMENT_ARRAY 0x8000
80 #define SEGMENT_BUFFER 0x4000
81 #define SEGMENT_MASK (SEN_INV_MAX_SEGMENT - 1)
82
83 #define BIT11_01(x) ((x >> 1) & 0x7ff)
84 #define BIT31_12(x) (x >> 12)
85
86 #define SEN_INV_INITIAL_N_SEGMENTS 512
87 #define MAX_CHUNK_RATIO 64
88
89 #define NEXT_ADDR(p) (((byte *)(p)) + sizeof *(p))
90
91 /* segment */
92
93 inline static uint16_t
94 segment_get(sen_inv *inv)
95 {
96   int i;
97   uint16_t seg;
98   char used[SEN_INV_MAX_SEGMENT];
99   memset(used, 0, SEN_INV_MAX_SEGMENT);
100   for (i = 0; i < SEN_INV_MAX_SEGMENT; i++) {
101     if ((seg = inv->header->ainfo[i]) != SEG_NOT_ASSIGNED) { used[seg] = 1; }
102     if ((seg = inv->header->binfo[i]) != SEG_NOT_ASSIGNED) { used[seg] = 1; }
103   }
104   for (seg = 0; used[seg] && seg < SEN_INV_MAX_SEGMENT; seg++) ;
105   return seg;
106 }
107
108 inline static sen_rc
109 segment_get_clear(sen_inv *inv, uint16_t *pseg)
110 {
111   uint16_t seg = segment_get(inv);
112   if (seg < SEN_INV_MAX_SEGMENT) {
113     void *p = NULL;
114     SEN_IO_SEG_REF(inv->seg, seg, p);
115     if (!p) { return sen_memory_exhausted; }
116     memset(p, 0, SEN_INV_SEGMENT_SIZE);
117     SEN_IO_SEG_UNREF(inv->seg, seg);
118     *pseg = seg;
119     return sen_success;
120   } else {
121     return sen_memory_exhausted;
122   }
123 }
124
125 inline static sen_rc
126 buffer_segment_new(sen_inv *inv, uint16_t *segno)
127 {
128   uint16_t lseg, pseg;
129   if (*segno < SEN_INV_MAX_SEGMENT) {
130     if (inv->header->binfo[*segno] != SEG_NOT_ASSIGNED) {
131       return sen_invalid_argument;
132     }
133     lseg = *segno;
134   } else {
135     for (lseg = 0; lseg < SEN_INV_MAX_SEGMENT; lseg++) {
136       if (inv->header->binfo[lseg] == SEG_NOT_ASSIGNED) { break; }
137     }
138     if (lseg == SEN_INV_MAX_SEGMENT) { return sen_memory_exhausted; }
139     *segno = lseg;
140   }
141   pseg = segment_get(inv);
142   if (pseg < SEN_INV_MAX_SEGMENT) {
143     inv->header->binfo[lseg] = pseg;
144     if (lseg >= inv->header->bmax) { inv->header->bmax = lseg + 1; }
145     return sen_success;
146   } else {
147     return sen_memory_exhausted;
148   }
149 }
150
151 void
152 sen_inv_seg_expire(sen_inv *inv, int32_t threshold)
153 {
154   uint16_t seg;
155   uint32_t th, nmaps;
156   if (inv->v08p) { sen_inv_seg_expire08(inv); return; }
157   th = (threshold < 0) ? (inv->header->initial_n_segments * 2) : (uint32_t) threshold;
158   if ((nmaps = inv->seg->nmaps) <= th) { return; }
159   for (seg = inv->header->bmax; seg && (inv->seg->nmaps > th); seg--) {
160     uint16_t pseg = inv->header->binfo[seg - 1];
161     if (pseg != SEG_NOT_ASSIGNED) {
162       sen_io_mapinfo *info = &inv->seg->maps[pseg];
163       uint32_t *pnref = &inv->seg->nrefs[pseg];
164       if (info->map && !*pnref) { sen_io_seg_expire(inv->seg, pseg, 0); }
165     }
166   }
167   for (seg = inv->header->amax; seg && (inv->seg->nmaps > th); seg--) {
168     uint16_t pseg = inv->header->ainfo[seg - 1];
169     if (pseg != SEG_NOT_ASSIGNED) {
170       sen_io_mapinfo *info = &inv->seg->maps[pseg];
171       uint32_t *pnref = &inv->seg->nrefs[pseg];
172       if (info->map && !*pnref) { sen_io_seg_expire(inv->seg, pseg, 0); }
173     }
174   }
175   SEN_LOG(sen_log_notice, "expired(%d) (%u -> %u)", threshold, nmaps, inv->seg->nmaps);
176 }
177
178 /* chunk */
179
180 inline static sen_rc
181 chunk_new(sen_inv *inv, uint32_t *res, uint32_t size)
182 {
183   int i, j;
184   uint32_t n = size / SEN_INV_CHUNK_SIZE;
185   int max_chunk = inv->header->initial_n_segments * MAX_CHUNK_RATIO;
186   uint32_t base_seg = sen_io_base_seg(inv->chunk);
187   if (n * SEN_INV_CHUNK_SIZE < size) { n++; }
188   for (i = 0, j = -1; i < max_chunk; i++) {
189     if (inv->header->chunks[i]) {
190       j = i;
191     } else {
192       if (i - j == n) {
193         if (res) { *res = j + 1; }
194         while (j < i) {
195           inv->header->chunks[++j] = 1;
196         }
197         return sen_success;
198       }
199       if ((i + base_seg)/ N_CHUNKS_PER_FILE !=
200           (i + base_seg + 1) / N_CHUNKS_PER_FILE) { j = i; }
201     }
202   }
203   SEN_LOG(sen_log_crit, "index full. set bigger value to initial_n_segments. current value = %d",
204           inv->header->initial_n_segments);
205   return sen_memory_exhausted;
206 }
207
208 inline static sen_rc
209 chunk_free(sen_inv *inv, int start, uint32_t size)
210 {
211   uint32_t i, n = size / SEN_INV_CHUNK_SIZE;
212   if (n * SEN_INV_CHUNK_SIZE < size) { n++; }
213   for (i = 0; i < n; i++) {
214     inv->header->chunks[start + i] = 0;
215   }
216   return sen_success;
217 }
218
219 /* buffer */
220
221 typedef struct {
222   uint32_t tid;
223   uint32_t size_in_chunk;
224   uint32_t pos_in_chunk;
225   uint16_t size_in_buffer;
226   uint16_t pos_in_buffer;
227 } buffer_term;
228
229 typedef struct {
230   uint16_t step;
231   uint16_t jump;
232 } buffer_rec;
233
234 typedef struct {
235   uint32_t chunk;
236   uint32_t chunk_size;
237   uint32_t buffer_free;
238   uint16_t nterms;
239   uint16_t nterms_void;
240 } buffer_header;
241
242 struct sen_inv_buffer {
243   buffer_header header;
244   buffer_term terms[(SEN_INV_SEGMENT_SIZE - sizeof(buffer_header))/sizeof(buffer_term)];
245 };
246
247 typedef struct sen_inv_buffer buffer;
248
249 inline static uint16_t
250 buffer_open(sen_inv *inv, uint32_t pos, buffer_term **bt, buffer **b)
251 {
252   byte *p = NULL;
253   uint16_t lseg = (uint16_t) (pos >> W_OF_SEGMENT);
254   uint16_t pseg = inv->header->binfo[lseg];
255   if (pseg != SEG_NOT_ASSIGNED) {
256     SEN_IO_SEG_REF(inv->seg, pseg, p);
257     if (!p) { return SEG_NOT_ASSIGNED; }
258     if (b) { *b = (buffer *)p; }
259     if (bt) { *bt = (buffer_term *)(p + (pos & BUFFER_MASK_IN_A_SEGMENT)); }
260   }
261   return pseg;
262 }
263
264 inline static sen_rc
265 buffer_close(sen_inv *inv, uint16_t pseg)
266 {
267   if (pseg >= SEN_INV_MAX_SEGMENT) {
268     SEN_LOG(sen_log_notice, "invalid pseg buffer_close(%d)", pseg);
269     return sen_invalid_argument;
270   }
271   SEN_IO_SEG_UNREF(inv->seg, pseg);
272   return sen_success;
273 }
274
275 inline static uint16_t
276 buffer_open_if_capable(sen_inv *inv, int32_t seg, int size, buffer **b)
277 {
278   uint16_t pseg;
279   uint32_t pos = ((uint32_t) seg) * SEN_INV_SEGMENT_SIZE;
280   if ((pseg = buffer_open(inv, pos, NULL, b)) != SEG_NOT_ASSIGNED) {
281     uint16_t nterms = (*b)->header.nterms - (*b)->header.nterms_void;
282     if (!((nterms < 4096 ||
283            (inv->header->total_chunk_size >> ((nterms >> 8) - 6))
284            > (*b)->header.chunk_size) &&
285           ((*b)->header.buffer_free >= size + sizeof(buffer_term)))) {
286       buffer_close(inv, pseg);
287       return SEG_NOT_ASSIGNED;
288     }
289   }
290   return pseg;
291 }
292
293 inline static uint16_t
294 buffer_new(sen_inv *inv, int size, uint32_t *pos,
295            buffer_term **bt, buffer_rec **br, buffer **bp, int hint)
296 {
297   buffer *b;
298   uint16_t nseg0 = inv->header->initial_n_segments;
299   uint16_t pseg, seg, offset, seg0 = hint % nseg0;
300   uint16_t segmax = (uint16_t) (inv->header->total_chunk_size >> 7) + nseg0;
301   if (size + sizeof(buffer_header) + sizeof(buffer_term) > SEN_INV_SEGMENT_SIZE) {
302     return SEG_NOT_ASSIGNED;
303   }
304   for (seg = seg0; seg < segmax; seg += nseg0) {
305     if (inv->header->binfo[seg] == SEG_NOT_ASSIGNED) { break; }
306     if ((pseg = buffer_open_if_capable(inv, seg, size, &b)) != SEG_NOT_ASSIGNED) {
307       goto exit;
308     }
309   }
310   if (seg >= segmax) {
311     for (seg = (seg0 + 1) % nseg0; seg != seg0; seg = (seg + 1) % nseg0) {
312       if (inv->header->binfo[seg] == SEG_NOT_ASSIGNED) { break; }
313       if ((pseg = buffer_open_if_capable(inv, seg, size, &b)) != SEG_NOT_ASSIGNED) {
314         goto exit;
315       }
316     }
317     if (seg == seg0) {
318       for (seg = nseg0; seg < SEN_INV_MAX_SEGMENT; seg++) {
319         if (inv->header->binfo[seg] == SEG_NOT_ASSIGNED) { break; }
320         if ((pseg = buffer_open_if_capable(inv, seg, size, &b)) != SEG_NOT_ASSIGNED) {
321           goto exit;
322         }
323       }
324     }
325   }
326   SEN_LOG(sen_log_debug, "inv=%p new seg=%d", inv, seg);
327   if (buffer_segment_new(inv, &seg) ||
328       (pseg = buffer_open(inv, seg * SEN_INV_SEGMENT_SIZE, NULL, &b)) == SEG_NOT_ASSIGNED) {
329     return SEG_NOT_ASSIGNED;
330   }
331   memset(b, 0, SEN_INV_SEGMENT_SIZE);
332   b->header.buffer_free = SEN_INV_SEGMENT_SIZE - sizeof(buffer_header);
333   b->header.chunk = CHUNK_NOT_ASSIGNED;
334   b->header.chunk_size = 0;
335 exit :
336   if (b->header.nterms_void) {
337     for (offset = 0; offset < b->header.nterms; offset++) {
338       if (!b->terms[offset].tid) { break; }
339     }
340     if (offset == b->header.nterms) {
341       SEN_LOG(sen_log_notice, "inconsistent buffer(%d)", seg);
342       b->header.nterms_void = 0;
343       b->header.nterms++;
344       b->header.buffer_free -= size + sizeof(buffer_term);
345     } else {
346       b->header.nterms_void--;
347       b->header.buffer_free -= size;
348     }
349   } else {
350     offset = b->header.nterms++;
351     b->header.buffer_free -= size + sizeof(buffer_term);
352   }
353   *pos = seg * SEN_INV_SEGMENT_SIZE
354     + sizeof(buffer_header) + sizeof(buffer_term) * offset;
355   *bt = &b->terms[offset];
356   *br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms]) + b->header.buffer_free);
357   *bp = b;
358   return pseg;
359 }
360
361 typedef struct {
362   uint32_t rid;
363   uint32_t sid;
364 } docid;
365
366 #define BUFFER_REC_DEL(r)  ((r)->jump = 1)
367 #define BUFFER_REC_DELETED(r) ((r)->jump == 1)
368
369 #define BUFFER_REC_AT(b,pos) ((buffer_rec *)(b) + (pos))
370 #define BUFFER_REC_POS(b,rec) ((uint16_t)((rec) - (buffer_rec *)(b)))
371
372 inline static void
373 buffer_term_dump(buffer *b, buffer_term *bt)
374 {
375   int pos, rid, sid;
376   uint8_t *p;
377   buffer_rec *r;
378   SEN_LOG(sen_log_debug,
379           "b=(%x %u %u %u)", b->header.chunk, b->header.chunk_size, b->header.buffer_free, b->header.nterms);
380   SEN_LOG(sen_log_debug,
381           "bt=(%u %u %u %u %u)", bt->tid, bt->size_in_chunk, bt->pos_in_chunk, bt->size_in_buffer, bt->pos_in_buffer);
382   for (pos = bt->pos_in_buffer; pos; pos = r->step) {
383     r = BUFFER_REC_AT(b, pos);
384     p = NEXT_ADDR(r);
385     SEN_B_DEC(rid, p);
386     SEN_B_DEC(sid, p);
387     SEN_LOG(sen_log_debug, "%d=(%d:%d),(%d:%d)", pos, r->jump, r->step, rid, sid);
388   }
389 }
390
391 static buffer_term *tmp_bt;
392
393 inline static sen_rc
394 check_jump(buffer *b, buffer_rec *r, int j)
395 {
396   uint16_t i = BUFFER_REC_POS(b, r);
397   uint8_t *p;
398   buffer_rec *r2;
399   docid id, id2;
400   if (!j) { return sen_success; }
401   p = NEXT_ADDR(r);
402   SEN_B_DEC(id.rid, p);
403   SEN_B_DEC(id.sid, p);
404   if (j == 1) {
405     SEN_LOG(sen_log_debug, "deleting! %d(%d:%d)", i, id.rid, id.sid);
406     return sen_success;
407   }
408   r2 = BUFFER_REC_AT(b, j);
409   p = NEXT_ADDR(r2);
410   SEN_B_DEC(id2.rid, p);
411   SEN_B_DEC(id2.sid, p);
412   if (r2->step == i) {
413     SEN_LOG(sen_log_emerg, "cycle! %d(%d:%d)<->%d(%d:%d)", i, id.rid, id.sid, j, id2.rid, id2.sid);
414     buffer_term_dump(b, tmp_bt);
415     return sen_abnormal_error;
416   }
417   if (id2.rid < id.rid || (id2.rid == id.rid && id2.sid <= id.sid)) {
418     SEN_LOG(sen_log_crit, "invalid jump! %d(%d:%d)(%d:%d)->%d(%d:%d)(%d:%d)", i, r->jump, r->step, id.rid, id.sid, j, r2->jump, r2->step, id2.rid, id2.sid);
419     return sen_abnormal_error;
420   }
421   return sen_success;
422 }
423
424 inline static int
425 buffer_check(buffer *b, uint32_t *nerrors)
426 {
427   uint8_t *sbp = NULL;
428   uint16_t nextb;
429   buffer_rec *br;
430   buffer_term *bt;
431   int n = b->header.nterms;
432   int nterms = 0;
433   for (bt = b->terms; n; n--, bt++) {
434     uint32_t rid = 0, sid = 0;
435     if (!bt->tid) { continue; }
436     nterms++;
437     for (nextb = bt->pos_in_buffer; nextb; nextb = br->step) {
438       uint32_t lrid = rid, lsid = sid;
439       br = BUFFER_REC_AT(b, nextb);
440       if (check_jump(b, br, br->jump)) { (*nerrors)++; }
441       sbp = NEXT_ADDR(br);
442       SEN_B_DEC(rid, sbp);
443       SEN_B_DEC(sid, sbp);
444       if (lrid > rid || (lrid == rid && lsid >= sid)) {
445         SEN_LOG(sen_log_crit, "brokeng!! tid=%d (%d:%d) -> (%d:%d)", bt->tid, lrid, lsid, rid, sid);
446         (*nerrors)++;
447         break;
448       }
449     }
450   }
451   return nterms;
452 }
453
454 int
455 sen_inv_check(sen_inv *inv)
456 {
457   buffer *b;
458   uint32_t pos, total_nterms = 0, nerrors = 0;
459   uint16_t nseg0 = inv->header->initial_n_segments;
460   uint16_t pseg, seg, nsegs = 0;
461   uint16_t segmax = (uint16_t) (inv->header->total_chunk_size >> 7) + nseg0;
462   for (seg = 0; seg < segmax; seg++) {
463     if (inv->header->binfo[seg] == SEG_NOT_ASSIGNED) { continue; }
464     pos = ((uint32_t) seg) * SEN_INV_SEGMENT_SIZE;
465     if ((pseg = buffer_open(inv, pos, NULL, &b)) == SEG_NOT_ASSIGNED) { continue; }
466     nsegs++;
467     total_nterms += buffer_check(b, &nerrors);
468     buffer_close(inv, pseg);
469   }
470   sen_log("sen_inv_check done nsegs=%d total_nterms=%d", nsegs, total_nterms);
471   return nerrors;
472 }
473
474 inline static sen_rc
475 set_jump_r(buffer *b, buffer_rec *from, int to)
476 {
477   int i, j, max_jump = 100;
478   buffer_rec *r, *r2;
479   for (r = from, j = to; j > 1 && max_jump--; r = BUFFER_REC_AT(b, r->step)) {
480     r2 = BUFFER_REC_AT(b, j);
481     if (r == r2) { break; }
482     if (BUFFER_REC_DELETED(r2)) { break; }
483     if (j == (i = r->jump)) { break; }
484     if (j == r->step) { break; }
485     if (check_jump(b, r, j)) { return sen_internal_error; }
486     r->jump = j;
487     j = i;
488     if (!r->step) { return sen_abnormal_error; }
489   }
490   return sen_success;
491 }
492
493 #define GET_NUM_BITS(x,n) {\
494   n = x;\
495   n = (n & 0x55555555) + ((n >> 1) & 0x55555555);\
496   n = (n & 0x33333333) + ((n >> 2) & 0x33333333);\
497   n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F);\
498   n = (n & 0x00FF00FF) + ((n >> 8) & 0x00FF00FF);\
499   n = (n & 0x0000FFFF) + ((n >>16) & 0x0000FFFF);\
500 }
501
502 inline static sen_rc
503 buffer_put(buffer *b, buffer_term *bt, buffer_rec *rnew, uint8_t *bs,
504            sen_inv_updspec *u, int size)
505 {
506   uint8_t *p;
507   sen_rc rc = sen_success;
508   docid id_curr = {0, 0}, id_start = {0, 0}, id_post = {0, 0};
509   buffer_rec *r_curr, *r_start = NULL;
510   uint16_t last = 0, *lastp = &bt->pos_in_buffer, pos = BUFFER_REC_POS(b, rnew);
511   int vdelta = 0, delta, delta0 = 0, vhops = 0, nhops = 0, reset = 1;
512
513   tmp_bt = bt; // test
514
515   memcpy(NEXT_ADDR(rnew), bs, size - sizeof(buffer_rec));
516   //  sen_log("tid=%d u->rid=%d u->sid=%d", bt->tid, u->rid, u->sid);
517   for (;;) {
518     //    sen_log("*lastp=%d", *lastp);
519     if (!*lastp) {
520       rnew->step = 0;
521       rnew->jump = 0;
522       *lastp = pos;
523       if (bt->size_in_buffer++ > 1) {
524         buffer_rec *rhead = BUFFER_REC_AT(b, bt->pos_in_buffer);
525         rhead->jump = pos;
526         if (!(bt->size_in_buffer & 1)) {
527           int n;
528           buffer_rec *r = BUFFER_REC_AT(b, rhead->step), *r2;
529           GET_NUM_BITS(bt->size_in_buffer, n);
530           while (n-- && (r->jump > 1)) {
531             r2 = BUFFER_REC_AT(b, r->jump);
532             if (BUFFER_REC_DELETED(r2)) { break; }
533             r = r2;
534           }
535           if (r != rnew) { set_jump_r(b, r, last); }
536         }
537       }
538       break;
539     }
540     r_curr = BUFFER_REC_AT(b, *lastp);
541     p = NEXT_ADDR(r_curr);
542     SEN_B_DEC(id_curr.rid, p);
543     SEN_B_DEC(id_curr.sid, p);
544     if (id_curr.rid < id_post.rid ||
545         (id_curr.rid == id_post.rid && id_curr.sid < id_post.sid)) {
546       SEN_LOG(sen_log_emerg, "loop found!!! (%d:%d)->(%d:%d)",
547               id_post.rid, id_post.sid, id_curr.rid, id_curr.sid);
548       buffer_term_dump(b, bt);
549       /* abandon corrupt list */
550       bt->pos_in_buffer = 0;
551       bt->size_in_buffer = 0;
552       lastp = &bt->pos_in_buffer;
553       rc = sen_invalid_format;
554       continue;
555     }
556     id_post.rid = id_curr.rid;
557     id_post.sid = id_curr.sid;
558     if (u->rid < id_curr.rid || (u->rid == id_curr.rid && u->sid <= id_curr.sid)) {
559       uint16_t step = *lastp, jump = r_curr->jump;
560       if (u->rid == id_curr.rid) {
561         if (u->sid == 0) {
562           while (id_curr.rid == u->rid) {
563             BUFFER_REC_DEL(r_curr);
564             if (!(step = r_curr->step)) { break; }
565             r_curr = BUFFER_REC_AT(b, step);
566             p = NEXT_ADDR(r_curr);
567             SEN_B_DEC(id_curr.rid, p);
568             SEN_B_DEC(id_curr.sid, p);
569           }
570         } else if (u->sid == id_curr.sid) {
571           BUFFER_REC_DEL(r_curr);
572           step = r_curr->step;
573         }
574       }
575       rnew->step = step;
576       rnew->jump = check_jump(b, rnew, jump) ? 0 : jump;
577       *lastp = pos;
578       break;
579     }
580
581     if (reset) {
582       r_start = r_curr;
583       id_start.rid = id_curr.rid;
584       id_start.sid = id_curr.sid;
585       if (!(delta0 = u->rid - id_start.rid)) { delta0 = u->sid - id_start.sid; }
586       nhops = 0;
587       vhops = 1;
588       vdelta = delta0 >> 1;
589     } else {
590       if (!(delta = id_curr.rid - id_start.rid)) { delta = id_curr.sid - id_start.sid; }
591       if (vdelta < delta) {
592         vdelta += (delta0 >> ++vhops);
593         r_start = r_curr;
594       }
595       if (nhops > vhops) {
596         set_jump_r(b, r_start, *lastp);
597       } else {
598         nhops++;
599       }
600     }
601
602     last = *lastp;
603     lastp = &r_curr->step;
604     reset = 0;
605     {
606       uint16_t posj = r_curr->jump;
607       if (posj > 1) {
608         buffer_rec *rj = BUFFER_REC_AT(b, posj);
609         if (!BUFFER_REC_DELETED(rj)) {
610           docid idj;
611           p = NEXT_ADDR(rj);
612           SEN_B_DEC(idj.rid, p);
613           SEN_B_DEC(idj.sid, p);
614           if (idj.rid < u->rid || (idj.rid == u->rid && idj.sid < u->sid)) {
615             last = posj;
616             lastp = &rj->step;
617           } else {
618             reset = 1;
619           }
620         }
621       }
622     }
623   }
624   // buffer_check(b);
625   return rc;
626 }
627
628 /* array */
629
630 inline static uint32_t *
631 array_at(sen_inv *inv, uint32_t id)
632 {
633   byte *p = NULL;
634   uint16_t seg, pseg;
635   if (id > SEN_SYM_MAX_ID) { return NULL; }
636   seg = id >> W_OF_ARRAY;
637   if ((pseg = inv->header->ainfo[seg]) == SEG_NOT_ASSIGNED) { return NULL; }
638   SEN_IO_SEG_REF(inv->seg, pseg, p);
639   if (!p) { return NULL; }
640   return (uint32_t *)(p + (id & ARRAY_MASK_IN_A_SEGMENT) * sizeof(uint32_t));
641 }
642
643 inline static uint32_t *
644 array_get(sen_inv *inv, uint32_t id)
645 {
646   byte *p = NULL;
647   uint16_t seg, pseg;
648   if (id > SEN_SYM_MAX_ID) { return NULL; }
649   seg = id >> W_OF_ARRAY;
650   if ((pseg = inv->header->ainfo[seg]) == SEG_NOT_ASSIGNED) {
651     if (segment_get_clear(inv, &pseg)) { return NULL; }
652     inv->header->ainfo[seg] = pseg;
653     if (seg >= inv->header->amax) { inv->header->amax = seg + 1; }
654   }
655   SEN_IO_SEG_REF(inv->seg, pseg, p)
656   if (!p) { return NULL; }
657   return (uint32_t *)(p + (id & ARRAY_MASK_IN_A_SEGMENT) * sizeof(uint32_t));
658 }
659
660 inline static void
661 array_unref(sen_inv *inv, uint32_t id)
662 {
663   SEN_IO_SEG_UNREF(inv->seg, inv->header->ainfo[id >> W_OF_ARRAY]);
664 }
665
666 /* updspec */
667
668 sen_inv_updspec *
669 sen_inv_updspec_open(uint32_t rid, uint32_t sid)
670 {
671   sen_inv_updspec *u;
672   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
673   if (!(u = SEN_MALLOC(sizeof(sen_inv_updspec)))) { return NULL; }
674   u->rid = rid;
675   u->sid = sid;
676   u->score = 0;
677   u->tf = 0;
678   u->atf = 0;
679   u->pos = NULL;
680   u->tail = NULL;
681   u->vnodes = NULL;
682   return u;
683 }
684
685 #define SEN_INV_MAX_TF 0x1ffff
686
687 sen_rc
688 sen_inv_updspec_add(sen_inv_updspec *u, int pos, int32_t weight)
689 {
690   struct _sen_inv_pos *p;
691   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
692   u->atf++;
693   if (u->tf >= SEN_INV_MAX_TF) { return sen_success; }
694   if (!(p = SEN_MALLOC(sizeof(struct _sen_inv_pos)))) {
695     return sen_memory_exhausted;
696   }
697   u->score += weight;
698   p->pos = pos;
699   p->next = NULL;
700   if (u->tail) {
701     u->tail->next = p;
702   } else {
703     u->pos = p;
704   }
705   u->tail = p;
706   u->tf++;
707   return sen_success;
708 }
709
710 int
711 sen_inv_updspec_cmp(sen_inv_updspec *a, sen_inv_updspec *b)
712 {
713   struct _sen_inv_pos *pa, *pb;
714   if (a->rid != b->rid) { return a->rid - b->rid; }
715   if (a->sid != b->sid) { return a->sid - b->sid; }
716   if (a->score != b->score) { return a->score - b->score; }
717   if (a->tf != b->tf) { return a->tf - b->tf; }
718   for (pa = a->pos, pb = b->pos; pa && pb; pa = pa->next, pb = pb->next) {
719     if (pa->pos != pb->pos) { return pa->pos - pb->pos; }
720   }
721   if (pa) { return 1; }
722   if (pb) { return -1; }
723   return 0;
724 }
725
726 sen_rc
727 sen_inv_updspec_close(sen_inv_updspec *u)
728 {
729   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
730   struct _sen_inv_pos *p = u->pos, *q;
731   while (p) {
732     q = p->next;
733     SEN_FREE(p);
734     p = q;
735   }
736   SEN_FREE(u);
737   return sen_success;
738 }
739
740 inline static uint8_t *
741 encode_rec(sen_inv_updspec *u, unsigned int *size, int deletep)
742 {
743   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
744   uint8_t *br, *p;
745   struct _sen_inv_pos *pp;
746   uint32_t lpos, tf, score;
747   if (deletep) {
748     tf = 0;
749     score = 0;
750   } else {
751     tf = u->tf;
752     score = u->score;
753   }
754   if (!(br = SEN_MALLOC((tf + 4) * 5))) {
755     return NULL;
756   }
757   p = br;
758   SEN_B_ENC(u->rid, p);
759   SEN_B_ENC(u->sid, p);
760   if (!score) {
761     SEN_B_ENC(tf * 2, p);
762   } else {
763     SEN_B_ENC(tf * 2 + 1, p);
764     SEN_B_ENC(score, p);
765   }
766   for (lpos = 0, pp = u->pos; pp && tf--; lpos = pp->pos, pp = pp->next) {
767     SEN_B_ENC(pp->pos - lpos, p);
768   }
769   while (((intptr_t)p & 0x03)) { *p++ = 0; }
770   *size = (unsigned int) ((p - br) + sizeof(buffer_rec));
771   return br;
772 }
773
774 inline static int
775 sym_deletable(uint32_t tid, sen_set *h)
776 {
777   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
778   sen_inv_updspec **u;
779   if (!h) { return 1; }
780   if (!sen_set_at(h, &tid, (void **) &u)) {
781     return (ERRP(ctx, SEN_ERROR)) ? 0 : 1;
782   }
783   if (!(*u)->tf || !(*u)->sid) { return 1; }
784   return 0;
785 }
786
787 typedef struct {
788   sen_inv *inv;
789   sen_set *h;
790 } sis_deletable_arg;
791
792 static int
793 sis_deletable(sen_id tid, void *arg)
794 {
795   uint32_t *a;
796   sen_set *h = ((sis_deletable_arg *)arg)->h;
797   sen_inv *inv = ((sis_deletable_arg *)arg)->inv;
798   if ((a = array_at(inv, tid))) {
799     if (*a) {
800       array_unref(inv, tid);
801       return 0;
802     }
803     array_unref(inv, tid);
804   }
805   return sym_deletable(tid, h);
806 }
807
808 inline static void
809 sym_delete(sen_inv *inv, uint32_t tid, sen_set *h)
810 {
811   sis_deletable_arg arg = {inv, h};
812   if ((inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON)) {
813     sen_sym_pocket_decr(inv->lexicon, tid);
814   }
815   if (inv->lexicon->flags & SEN_SYM_WITH_SIS) {
816     sen_sym_del_with_sis(inv->lexicon, tid, sis_deletable, &arg);
817     /*
818     uint32_t *a;
819     while ((tid = sen_sym_del_with_sis(inv->lexicon, tid))) {
820       if ((a = array_at(inv, tid))) {
821         if (*a) {
822           array_unref(inv, tid);
823           break;
824         }
825         array_unref(inv, tid);
826       }
827       if (!sym_deletable(tid, h)) { break; }
828     }
829     */
830   } else {
831     if (sym_deletable(tid, h)) {
832       sen_sym_del(inv->lexicon, _sen_sym_key(inv->lexicon, tid));
833     }
834   }
835 }
836
837 typedef struct {
838   sen_id rid;
839   uint32_t sid;
840   uint32_t tf;
841   uint32_t score;
842   uint32_t flags;
843 } docinfo;
844
845 #define SEN_C_ENC(dgap,tf,p)\
846 {\
847   uint8_t *p2 = (uint8_t *)p;\
848   uint32_t _d = dgap;\
849   uint32_t _t = tf;\
850   if (_d < 0x46 && _t <= 2) {\
851     *p2++ = (_d << 1) + (_t - 1);\
852   } else if (_d < 0x46 && _t <= 6) {\
853     *p2++ = 0xc0 + (_d >> 6);\
854     *p2++ = (_d << 2) + (_t - 3);\
855   } else if (_d < 0x1000 && _t <= 4) {\
856     *p2++ = 0xc0 + (_d >> 6);\
857     *p2++ = (_d << 2) + (_t - 1);\
858   } else if (_d < 0x4000 && _t <= 0x40) {\
859     *p2++ = 0x90 + (_d >> 10);\
860     *p2++ = (_d >> 2);\
861     *p2++ = (_d << 6) + (_t - 1);\
862   } else if (_d < 0x80000 && _t <= 4) {\
863     *p2++ = 0xa0 + (_d >> 14);\
864     *p2++ = (_d >> 6);\
865     *p2++ = (_d << 2) + (_t - 1);\
866   } else {\
867     *p2++ = 0x8f;\
868     SEN_B_ENC(_d, p2);\
869     SEN_B_ENC(_t, p2);\
870   }\
871   p = p2;\
872 }
873
874 #define SEN_C_DEC(dgap,tf,p)\
875 {\
876   uint8_t *p2 = (uint8_t *)p;\
877   uint32_t _v = *p2++;\
878   switch (_v >> 4) {\
879   case 0x08 :\
880     if (_v == 0x8f) {\
881       SEN_B_DEC(dgap, p2);\
882       SEN_B_DEC(tf, p2);\
883     } else {\
884       dgap = _v >> 1;\
885       tf = (_v & 1) + 1;\
886       break;\
887     }\
888     break;\
889   case 0x09 :\
890     dgap = ((_v - 0x90) << 10) + ((*p2++) << 2);\
891     _v = *p2++;\
892     dgap += _v >> 6;\
893     tf = (_v & 0x3f) + 1;\
894     break;\
895   case 0x0a :\
896   case 0x0b :\
897     dgap = ((_v - 0xa0) << 14) + ((*p2++) << 6);\
898     _v = *p2++;\
899     dgap += _v >> 2;\
900     tf = (_v & 3) + 1;\
901     break;\
902   case 0x0c :\
903   case 0x0d :\
904   case 0x0e :\
905   case 0x0f :\
906     dgap = (_v - 0xc0) << 6;\
907     _v = *p2++;\
908     dgap += _v >> 2;\
909     tf = (_v & 3) + 1;\
910     if (dgap < 0x46) { tf += 2; }\
911     break;\
912   default :\
913     dgap = _v >> 1;\
914     tf = (_v & 1) + 1;\
915     break;\
916   }\
917   p = p2;\
918 }
919
920 inline static sen_rc
921 buffer_flush(sen_inv *inv, sen_ctx *ctx, uint32_t seg, sen_set *h)
922 {
923   buffer *sb, *db = NULL;
924   sen_rc rc = sen_success;
925   sen_io_win sw, dw;
926   uint8_t *tc, *tp, *dc, *sc = NULL;
927   uint16_t ss, ds, pseg;
928   uint32_t scn, dcn, max_dest_chunk_size;
929   ss = inv->header->binfo[seg];
930   if (ss == SEG_NOT_ASSIGNED) { return sen_invalid_format; }
931   pseg = buffer_open(inv, seg * SEN_INV_SEGMENT_SIZE, NULL, &sb);
932   if (pseg == SEG_NOT_ASSIGNED) { return sen_memory_exhausted; }
933   if ((ds = segment_get(inv)) == SEN_INV_MAX_SEGMENT) {
934     buffer_close(inv, pseg);
935     return sen_memory_exhausted;
936   }
937   SEN_IO_SEG_REF(inv->seg, ds, db);
938   if (!db) {
939     buffer_close(inv, pseg);
940     return sen_memory_exhausted;
941   }
942   memset(db, 0, SEN_INV_SEGMENT_SIZE);
943   max_dest_chunk_size = sb->header.chunk_size + SEN_INV_SEGMENT_SIZE;
944   if (!(tc = SEN_MALLOC(max_dest_chunk_size * 2))) {
945     buffer_close(inv, pseg);
946     SEN_IO_SEG_UNREF(inv->seg, ds);
947     return sen_memory_exhausted;
948   }
949   tp = tc + max_dest_chunk_size;
950   if (chunk_new(inv, &dcn, max_dest_chunk_size)) {
951     buffer_close(inv, pseg);
952     SEN_IO_SEG_UNREF(inv->seg, ds);
953     SEN_FREE(tc);
954     return sen_memory_exhausted;
955   }
956   //  sen_log("db=%p ds=%d sb=%p seg=%d", db, ds, sb, seg);
957   if ((scn = sb->header.chunk) != CHUNK_NOT_ASSIGNED) {
958     sc = sen_io_win_map(inv->chunk, ctx, &sw, scn, 0, sb->header.chunk_size, SEN_IO_COPY);
959     if (!sc) {
960       SEN_LOG(sen_log_alert, "io_win_map(%d, %d) failed!", scn, sb->header.chunk_size);
961       buffer_close(inv, pseg);
962       SEN_IO_SEG_UNREF(inv->seg, ds);
963       SEN_FREE(tc);
964       chunk_free(inv, dcn, max_dest_chunk_size);
965       return sen_memory_exhausted;
966     }
967   }
968   dc = sen_io_win_map(inv->chunk, ctx, &dw, dcn, 0, max_dest_chunk_size, SEN_IO_UPDATE);
969   if (!dc) {
970     SEN_LOG(sen_log_alert, "io_win_map(%d, %d) failed!!", dcn, max_dest_chunk_size);
971     buffer_close(inv, pseg);
972     SEN_IO_SEG_UNREF(inv->seg, ds);
973     SEN_FREE(tc);
974     chunk_free(inv, dcn, max_dest_chunk_size);
975     if (scn != CHUNK_NOT_ASSIGNED) { sen_io_win_unmap(&sw); }
976     return sen_memory_exhausted;
977   }
978   {
979     uint8_t *sbp = NULL, *scp = NULL, *sce = NULL, *dcp = dc;
980     uint16_t nextb;
981     buffer_rec *br;
982     buffer_term *bt;
983     int n = sb->header.nterms;
984     int nterms_void = 0;
985     uint8_t *tpp, *tcp, *spp = NULL;
986     memcpy(db->terms, sb->terms, n * sizeof(buffer_term));
987     // sen_log(" scn=%d, dcn=%d, nterms=%d", sb->header.chunk, dcn, n);
988     for (bt = db->terms; n; n--, bt++) {
989       uint32_t ndf = 0, dgap_ = 0, sgap_ = 0;
990       docinfo cid = {0, 0, 0, 0, 0}, lid = {0, 0, 0, 0, 0}, bid = {0, 0};
991       tpp = tp; tcp = tc;
992       if (!bt->tid) {
993         nterms_void++;
994         continue;
995       }
996       if (sc) {
997         uint32_t o;
998         scp = sc + bt->pos_in_chunk;
999         sce = scp + bt->size_in_chunk;
1000         if (bt->size_in_chunk) {
1001           SEN_B_DEC(o, scp);
1002           sce = spp = scp + o;
1003         }
1004       }
1005       nextb = bt->pos_in_buffer;
1006       bt->pos_in_chunk = (uint32_t)(dcp - dc);
1007       bt->size_in_buffer = 0;
1008       bt->pos_in_buffer = 0;
1009
1010 #define GETNEXTC_() {\
1011   if (scp < sce) {\
1012     uint32_t dgap;\
1013     if (*scp == 0x8c) { cid.flags |= 1; scp++; } else { cid.flags &= ~1; }\
1014     if (*scp == 0x8d) { cid.flags ^= 2; scp++; }\
1015     if (*scp == 0x8e) { cid.flags ^= 4; scp++; }\
1016     SEN_C_DEC(dgap, cid.tf, scp);\
1017     cid.rid += dgap;\
1018     if (dgap) { cid.sid = 0; }\
1019     if (cid.flags & 4) { SEN_B_DEC(dgap, scp); } else { dgap = 0; }\
1020     if (cid.flags & 3) { SEN_B_DEC(cid.score, scp); } else { cid.score = 0; }\
1021     cid.sid += dgap + 1;\
1022   } else {\
1023     cid.rid = 0;\
1024   }\
1025 }
1026 #define GETNEXTC() {\
1027   if (scp < sce && cid.rid) { while (cid.tf--) { SEN_B_SKIP(spp); } }\
1028   GETNEXTC_();\
1029 }
1030 #define PUTNEXT_(id,pp) {\
1031   uint32_t dgap = id.rid - lid.rid;\
1032   uint32_t sgap = (dgap ? id.sid : id.sid - lid.sid);\
1033   if (sgap_) {\
1034     lid.flags &= ~1;\
1035     if (lid.score) {\
1036       if (!(lid.flags & 2)) {\
1037         if (id.score) {\
1038           lid.flags |= 2; *tcp++ = 0x8d;\
1039         } else {\
1040           lid.flags |= 1; *tcp++ = 0x8c;\
1041         }\
1042       }\
1043     } else {\
1044       if (!id.score && (lid.flags & 2)) { lid.flags &= ~2; *tcp++ = 0x8d; }\
1045     }\
1046     sgap_--;\
1047     if (sgap_) {\
1048       if (!(lid.flags & 4)) { lid.flags |= 4; *tcp++ = 0x8e; }\
1049     } else {\
1050       if (sgap == 1 && (lid.flags & 4)) { lid.flags &= ~4; *tcp++ = 0x8e; }\
1051     }\
1052     SEN_C_ENC(dgap_, lid.tf, tcp);\
1053     if (lid.flags & 4) { SEN_B_ENC(sgap_, tcp); }\
1054     if (lid.flags & 3) { SEN_B_ENC(lid.score, tcp); }\
1055   }\
1056   dgap_ = dgap;\
1057   lid.tf = id.tf;\
1058   sgap_ = sgap;\
1059   lid.score = id.score;\
1060   while (id.tf--) { SEN_B_COPY(tpp, pp); }\
1061   lid.rid = id.rid;\
1062   lid.sid = id.sid;\
1063 }
1064 #define PUTNEXTC() {\
1065   if (cid.rid) {\
1066     if (cid.tf) {\
1067       if (lid.rid > cid.rid || (lid.rid == cid.rid && lid.sid >= cid.sid)) {\
1068         SEN_LOG(sen_log_crit, "brokenc!! (%d:%d) -> (%d:%d)", lid.rid, lid.sid, bid.rid, bid.sid);\
1069         rc = sen_invalid_format;\
1070         break;\
1071       }\
1072       ndf++;\
1073       PUTNEXT_(cid, spp);\
1074     } else {\
1075       SEN_LOG(sen_log_crit, "invalid chunk(%d,%d)", bt->tid, cid.rid);\
1076       rc = sen_invalid_format;\
1077       break;\
1078     }\
1079   }\
1080   GETNEXTC_();\
1081 }
1082 #define GETNEXTB() {\
1083   if (nextb) {\
1084     uint32_t lrid = bid.rid, lsid = bid.sid;\
1085     br = BUFFER_REC_AT(sb, nextb);\
1086     sbp = NEXT_ADDR(br);\
1087     SEN_B_DEC(bid.rid, sbp);\
1088     SEN_B_DEC(bid.sid, sbp);\
1089     if (lrid > bid.rid || (lrid == bid.rid && lsid >= bid.sid)) {\
1090       SEN_LOG(sen_log_crit, "brokeng!! (%d:%d) -> (%d:%d)", lrid, lsid, bid.rid, bid.sid);\
1091       rc = sen_invalid_format;\
1092       break;\
1093     }\
1094     nextb = br->step;\
1095   } else {\
1096     bid.rid = 0;\
1097   }\
1098 }
1099 #define PUTNEXTB() {\
1100   if (bid.rid && bid.sid) {\
1101     SEN_B_DEC(bid.tf, sbp);\
1102     if (bid.tf > 1) {\
1103       if (lid.rid > bid.rid || (lid.rid == bid.rid && lid.sid >= bid.sid)) {\
1104         SEN_LOG(sen_log_crit, "brokenb!! (%d:%d) -> (%d:%d)", lid.rid, lid.sid, bid.rid, bid.sid);\
1105         rc = sen_invalid_format;\
1106         break;\
1107       }\
1108       if (bid.tf & 1) { SEN_B_DEC(bid.score, sbp); } else { bid.score = 0; }\
1109       bid.tf >>= 1;\
1110       ndf++;\
1111       PUTNEXT_(bid, sbp);\
1112     }\
1113   }\
1114   GETNEXTB();\
1115 }
1116
1117       GETNEXTC();
1118       GETNEXTB();
1119       for (;;) {
1120         if (bid.rid) {
1121           if (cid.rid) {
1122             if (cid.rid < bid.rid) {
1123               PUTNEXTC();
1124             } else {
1125               if (bid.rid < cid.rid) {
1126                 PUTNEXTB();
1127               } else {
1128                 if (bid.sid) {
1129                   if (cid.sid < bid.sid) {
1130                     PUTNEXTC();
1131                   } else {
1132                     if (bid.sid == cid.sid) { GETNEXTC(); }
1133                     PUTNEXTB();
1134                   }
1135                 } else {
1136                   GETNEXTC();
1137                 }
1138               }
1139             }
1140           } else {
1141             PUTNEXTB();
1142           }
1143         } else {
1144           if (cid.rid) {
1145             PUTNEXTC();
1146           } else {
1147             break;
1148           }
1149         }
1150       }
1151
1152       if (sgap_) {
1153         if (lid.score && !(lid.flags & 2)) { lid.flags |= 2; *tcp++ = 0x8d; }
1154         sgap_--;
1155         if (sgap_ && !(lid.flags & 4)) { lid.flags |= 4; *tcp++ = 0x8e; }
1156         SEN_C_ENC(dgap_, lid.tf, tcp);
1157         if (lid.flags & 4) { SEN_B_ENC(sgap_, tcp); }
1158         if (lid.flags & 2) { SEN_B_ENC(lid.score, tcp); }
1159       }
1160
1161 #define BTCLR {\
1162   bt->tid = 0;\
1163   bt->pos_in_chunk = 0;\
1164   bt->size_in_chunk = 0;\
1165   nterms_void++;\
1166 }
1167 #define BTSET {\
1168   uint32_t o = tcp - tc;\
1169   SEN_B_ENC(o, dcp);\
1170   memcpy(dcp, tc, o);\
1171   dcp += o;\
1172   o = tpp - tp;\
1173   memcpy(dcp, tp, o);\
1174   dcp += o;\
1175   bt->size_in_chunk = (uint32_t)((dcp - dc) - bt->pos_in_chunk);\
1176 }
1177
1178       {
1179         uint32_t *a;
1180         if (!ndf) {
1181           if ((a = array_at(inv, bt->tid))) {
1182             if (!(inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON)) {
1183               sen_sym_pocket_set(inv->lexicon, bt->tid, 0);
1184             }
1185             *a = 0;
1186             sym_delete(inv, bt->tid, h);
1187             array_unref(inv, bt->tid);
1188             BTCLR;
1189           } else {
1190             BTSET;
1191           }
1192         } else if (ndf == 1 && lid.rid < 0x100000 && lid.sid < 0x800 && lid.tf == 1 && lid.score == 0) {
1193           uint32_t pos_;
1194           spp = tp;
1195           SEN_B_DEC(pos_, spp);
1196           if (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON) {
1197             if (lid.sid == 1 && pos_ < 0x800 && (a = array_at(inv, bt->tid))) {
1198               *a = (lid.rid << 12) + (pos_ << 1) + 1;
1199               array_unref(inv, bt->tid);
1200               BTCLR;
1201             } else {
1202               BTSET;
1203             }
1204           } else {
1205             if (pos_ < 0x4000 && (a = array_at(inv, bt->tid))) {
1206               sen_sym_pocket_set(inv->lexicon, bt->tid, pos_);
1207               *a = (lid.rid << 12) + (lid.sid << 1) + 1;
1208               array_unref(inv, bt->tid);
1209               BTCLR;
1210             } else {
1211               BTSET;
1212             }
1213           }
1214         } else {
1215           BTSET;
1216         }
1217       }
1218     }
1219     db->header.chunk_size = (uint32_t)(dcp - dc);
1220     db->header.nterms_void = nterms_void;
1221     inv->header->total_chunk_size += db->header.chunk_size >> 10;
1222   }
1223   db->header.chunk = db->header.chunk_size ? dcn : CHUNK_NOT_ASSIGNED;
1224   db->header.buffer_free = SEN_INV_SEGMENT_SIZE
1225     - sizeof(buffer_header) - sb->header.nterms * sizeof(buffer_term);
1226   db->header.nterms = sb->header.nterms;
1227
1228   {
1229     uint32_t mc, ec;
1230     mc = (max_dest_chunk_size + SEN_INV_CHUNK_SIZE - 1) / SEN_INV_CHUNK_SIZE;
1231     ec = (db->header.chunk_size + SEN_INV_CHUNK_SIZE - 1) / SEN_INV_CHUNK_SIZE;
1232     while (ec < mc) {
1233       inv->header->chunks[dcn + ec++] = 0;
1234     }
1235   }
1236   buffer_close(inv, pseg);
1237   SEN_FREE(tc);
1238   SEN_IO_SEG_UNREF(inv->seg, ds);
1239   inv->header->binfo[seg] = ds;
1240   if (scn != CHUNK_NOT_ASSIGNED) {
1241     sen_io_win_unmap(&sw);
1242     chunk_free(inv, scn, sb->header.chunk_size);
1243     inv->header->total_chunk_size -= sb->header.chunk_size >> 10;
1244   }
1245   sen_io_win_unmap(&dw);
1246   return rc;
1247 }
1248
1249 /* inv */
1250
1251 sen_inv *
1252 sen_inv_create(const char *path, sen_sym *lexicon, uint32_t initial_n_segments)
1253 {
1254   int i, max_chunk;
1255   sen_io *seg, *chunk;
1256   sen_inv *inv;
1257   char path2[PATH_MAX];
1258   struct sen_inv_header *header;
1259   if ((lexicon->flags & 0x70000)) {
1260     return sen_inv_create08(path, lexicon, initial_n_segments);
1261   }
1262   if (strlen(path) + 6 >= PATH_MAX) { return NULL; }
1263   strcpy(path2, path);
1264   strcat(path2, ".c");
1265   if (!initial_n_segments) { initial_n_segments = SEN_INV_INITIAL_N_SEGMENTS; }
1266   if (initial_n_segments > SEN_INV_MAX_SEGMENT) {
1267     initial_n_segments = SEN_INV_MAX_SEGMENT;
1268   }
1269   max_chunk = initial_n_segments * MAX_CHUNK_RATIO;
1270   seg = sen_io_create(path, sizeof(struct sen_inv_header) + max_chunk,
1271                       SEN_INV_SEGMENT_SIZE, SEN_INV_MAX_SEGMENT,
1272                       sen_io_auto, SEN_INV_MAX_SEGMENT);
1273   if (!seg) { return NULL; }
1274   chunk = sen_io_create(path2, 0, SEN_INV_CHUNK_SIZE,
1275                         max_chunk, sen_io_auto, max_chunk);
1276   if (!chunk) {
1277     sen_io_close(seg);
1278     return NULL;
1279   }
1280   header = sen_io_header(seg);
1281   memcpy(header->idstr, SEN_INV_IDSTR, 16);
1282   for (i = 0; i < SEN_INV_MAX_SEGMENT; i++) {
1283     header->ainfo[i] = SEG_NOT_ASSIGNED;
1284     header->binfo[i] = SEG_NOT_ASSIGNED;
1285   }
1286   header->initial_n_segments = initial_n_segments;
1287   if (!(inv = SEN_GMALLOC(sizeof(sen_inv)))) {
1288     sen_io_close(seg);
1289     sen_io_close(chunk);
1290     return NULL;
1291   }
1292   inv->v08p = 0;
1293   inv->seg = seg;
1294   inv->chunk = chunk;
1295   inv->header = header;
1296   inv->lexicon = lexicon;
1297   inv->header->total_chunk_size = 0;
1298   return inv;
1299 }
1300
1301 sen_rc
1302 sen_inv_remove(const char *path)
1303 {
1304   sen_rc rc;
1305   char buffer[PATH_MAX];
1306   if (!path || strlen(path) > PATH_MAX - 4) { return sen_invalid_argument; }
1307   if ((rc = sen_sym_remove(path))) { goto exit; }
1308   snprintf(buffer, PATH_MAX, "%s.c", path);
1309   rc = sen_io_remove(buffer);
1310 exit :
1311   return rc;
1312 }
1313
1314 sen_inv *
1315 sen_inv_open(const char *path, sen_sym *lexicon)
1316 {
1317   sen_io *seg, *chunk;
1318   sen_inv *inv;
1319   char path2[PATH_MAX];
1320   struct sen_inv_header *header;
1321   if ((lexicon->flags & 0x70000)) {
1322     return sen_inv_open08(path, lexicon);
1323   }
1324   if (strlen(path) + 6 >= PATH_MAX) { return NULL; }
1325   strcpy(path2, path);
1326   strcat(path2, ".c");
1327   seg = sen_io_open(path, sen_io_auto, SEN_INV_MAX_SEGMENT);
1328   if (!seg) { return NULL; }
1329   chunk = sen_io_open(path2, sen_io_auto, SEN_INV_MAX_SEGMENT);
1330   if (!chunk) {
1331     sen_io_close(seg);
1332     return NULL;
1333   }
1334   header = sen_io_header(seg);
1335   if (memcmp(header->idstr, SEN_INV_IDSTR, 16)) {
1336     SEN_LOG(sen_log_notice, "inv_idstr (%s)", header->idstr);
1337     sen_io_close(seg);
1338     sen_io_close(chunk);
1339     return sen_inv_open08(path, lexicon);
1340   }
1341   if (!(inv = SEN_GMALLOC(sizeof(sen_inv)))) {
1342     sen_io_close(seg);
1343     sen_io_close(chunk);
1344     return NULL;
1345   }
1346   inv->v08p = 0;
1347   inv->seg = seg;
1348   inv->chunk = chunk;
1349   inv->header = header;
1350   inv->lexicon = lexicon;
1351   return inv;
1352 }
1353
1354 sen_rc
1355 sen_inv_close(sen_inv *inv)
1356 {
1357   sen_rc rc;
1358   if (!inv) { return sen_invalid_argument; }
1359   if ((rc = sen_io_close(inv->seg))) { return rc; }
1360   if ((rc = sen_io_close(inv->chunk))) { return rc; }
1361   SEN_GFREE(inv);
1362   return rc;
1363 }
1364
1365 sen_rc
1366 sen_inv_info(sen_inv *inv, uint64_t *seg_size, uint64_t *chunk_size)
1367 {
1368   sen_rc rc;
1369
1370   if (seg_size) {
1371     if ((rc = sen_io_size(inv->seg, seg_size))) {
1372       return rc;
1373     }
1374   }
1375
1376   if (chunk_size) {
1377     if ((rc = sen_io_size(inv->chunk, chunk_size))) {
1378       return rc;
1379     }
1380   }
1381
1382   return sen_success;
1383 }
1384
1385 sen_rc
1386 sen_inv_update(sen_inv *inv, uint32_t key, sen_inv_updspec *u, sen_set *h, int hint)
1387 {
1388   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1389   sen_rc rc = sen_success;
1390   buffer *b;
1391   uint8_t *bs;
1392   uint16_t pseg = 0;
1393   buffer_rec *br = NULL;
1394   buffer_term *bt;
1395   uint32_t pos = 0, size, *a;
1396   if (inv->v08p) {
1397     return sen_inv_update08(inv, key, u, h, hint);
1398   }
1399   // sen_log("key=%d tf=%d pos0=%d rid=%d", key, u->tf, u->pos->pos, u->rid);
1400   if (!u->tf || !u->sid) { return sen_inv_delete(inv, key, u, h); }
1401   if (u->sid > inv->header->smax) { inv->header->smax = u->sid; }
1402   if (!(a = array_get(inv, key))) { return sen_memory_exhausted; }
1403   if (!(bs = encode_rec(u, &size, 0))) { rc = sen_memory_exhausted; goto exit; }
1404   for (;;) {
1405     if (*a) {
1406       if (!(*a & 1)) {
1407         pos = *a;
1408         if ((pseg = buffer_open(inv, pos, &bt, &b)) == SEG_NOT_ASSIGNED) {
1409           rc = sen_memory_exhausted;
1410           goto exit;
1411         }
1412         if (b->header.buffer_free < size) {
1413           int bfb = b->header.buffer_free;
1414           SEN_LOG(sen_log_debug, "flushing *a=%d seg=%d(%p) free=%d",
1415                   *a, *a >> W_OF_SEGMENT, b, b->header.buffer_free);
1416           buffer_close(inv, pseg);
1417           if ((rc = buffer_flush(inv, ctx, pos >> W_OF_SEGMENT, h))) { goto exit; }
1418           if (*a != pos) {
1419             SEN_LOG(sen_log_debug, "sen_inv_update: *a changed %d->%d", *a, pos);
1420             continue;
1421           }
1422           if ((pseg = buffer_open(inv, pos, &bt, &b)) == SEG_NOT_ASSIGNED) {
1423             SEN_LOG(sen_log_crit, "buffer not found *a=%d", *a);
1424             rc = sen_memory_exhausted;
1425             goto exit;
1426           }
1427           SEN_LOG(sen_log_debug, "flushed  *a=%d seg=%d(%p) free=%d->%d nterms=%d v=%d",
1428                   *a, *a >> W_OF_SEGMENT, b, bfb, b->header.buffer_free,
1429                   b->header.nterms, b->header.nterms_void);
1430           if (b->header.buffer_free < size) {
1431             buffer_close(inv, pseg);
1432             SEN_LOG(sen_log_crit, "buffer(%d) is full (%d < %d) in sen_inv_update",
1433                     *a, b->header.buffer_free, size);
1434             /* todo: must be splitted */
1435             rc = sen_memory_exhausted;
1436             goto exit;
1437           }
1438         }
1439         b->header.buffer_free -= size;
1440         br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms])
1441                             + b->header.buffer_free);
1442       } else {
1443         sen_inv_updspec u2;
1444         uint32_t size2 = 0, v = *a;
1445         struct _sen_inv_pos pos2;
1446         if (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON) {
1447           pos2.pos = BIT11_01(v);
1448           pos2.next = NULL;
1449           u2.pos = &pos2;
1450           u2.rid = BIT31_12(v);
1451           u2.sid = 1;
1452           u2.tf = 1;
1453           u2.score = 0;
1454         } else {
1455           pos2.pos = sen_sym_pocket_get(inv->lexicon, key);
1456           pos2.next = NULL;
1457           u2.pos = &pos2;
1458           u2.rid = BIT31_12(v);
1459           u2.sid = BIT11_01(v);
1460           u2.tf = 1;
1461           u2.score = 0;
1462         }
1463         if (u2.rid != u->rid || u2.sid != u->sid) {
1464           uint8_t *bs2 = encode_rec(&u2, &size2, 0);
1465           if (!bs2) {
1466             SEN_LOG(sen_log_alert, "encode_rec on sen_inv_update failed !");
1467             rc = sen_memory_exhausted;
1468             goto exit;
1469           }
1470           pseg = buffer_new(inv, size + size2, &pos, &bt, &br, &b, hint);
1471           if (pseg == SEG_NOT_ASSIGNED) {
1472             SEN_FREE(bs2);
1473             goto exit;
1474           }
1475           bt->tid = key;
1476           bt->size_in_chunk = 0;
1477           bt->pos_in_chunk = 0;
1478           bt->size_in_buffer = 0;
1479           bt->pos_in_buffer = 0;
1480           if ((rc = buffer_put(b, bt, br, bs2, &u2, size2))) {
1481             SEN_FREE(bs2);
1482             buffer_close(inv, pseg);
1483             goto exit;
1484           }
1485           br = (buffer_rec *)(((byte *)br) + size2);
1486           SEN_FREE(bs2);
1487         }
1488       }
1489     }
1490     break;
1491   }
1492   if (!*a && (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON)) {
1493     sen_sym_pocket_incr(inv->lexicon, key);
1494   }
1495   if (!br) {
1496     if (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON) {
1497       if (u->rid < 0x100000 && u->sid == 1 &&
1498           u->tf == 1 && u->score == 0 && u->pos->pos < 0x800) {
1499         *a = (u->rid << 12) + (u->pos->pos << 1) + 1;
1500         goto exit;
1501       }
1502     } else {
1503       if (u->rid < 0x100000 && u->sid < 0x800 &&
1504           u->tf == 1 && u->score == 0 && u->pos->pos < 0x4000) {
1505         sen_sym_pocket_set(inv->lexicon, key, u->pos->pos);
1506         *a = (u->rid << 12) + (u->sid << 1) + 1;
1507         goto exit;
1508       }
1509     }
1510     pseg = buffer_new(inv, size, &pos, &bt, &br, &b, hint);
1511     if (pseg == SEG_NOT_ASSIGNED) { goto exit; }
1512     bt->tid = key;
1513     bt->size_in_chunk = 0;
1514     bt->pos_in_chunk = 0;
1515     bt->size_in_buffer = 0;
1516     bt->pos_in_buffer = 0;
1517   }
1518   rc = buffer_put(b, bt, br, bs, u, size);
1519   buffer_close(inv, pseg);
1520   if (!*a || (*a & 1)) {
1521     *a = pos;
1522     if (!(inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON)) {
1523       sen_sym_pocket_set(inv->lexicon, key, 0);
1524     }
1525   }
1526 exit :
1527   array_unref(inv, key);
1528   if (bs) { SEN_FREE(bs); }
1529   if (u->tf != u->atf) {
1530     SEN_LOG(sen_log_warning, "too many postings(%d) on '%s'. discarded %d.", u->atf, _sen_sym_key(inv->lexicon, key), u->atf - u->tf);
1531   }
1532   return rc;
1533 }
1534
1535 sen_rc
1536 sen_inv_delete(sen_inv *inv, uint32_t key, sen_inv_updspec *u, sen_set *h)
1537 {
1538   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1539   sen_rc rc = sen_success;
1540   buffer *b;
1541   uint16_t pseg;
1542   uint8_t *bs = NULL;
1543   buffer_rec *br;
1544   buffer_term *bt;
1545   uint32_t size, *a;
1546   if (inv->v08p) {
1547     return sen_inv_delete08(inv, key, u, h);
1548   }
1549   if (!(a = array_at(inv, key))) { return sen_invalid_argument; }
1550   for (;;) {
1551     if (!*a) { goto exit; }
1552     if (*a & 1) {
1553       uint32_t rid = BIT31_12(*a);
1554       uint32_t sid = BIT11_01(*a);
1555       if (u->rid == rid && (!u->sid || u->sid == sid)) {
1556         *a = 0;
1557         sym_delete(inv, key, h);
1558       }
1559       goto exit;
1560     }
1561     if (!(bs = encode_rec(u, &size, 1))) {
1562       rc = sen_memory_exhausted;
1563       goto exit;
1564     }
1565     if ((pseg = buffer_open(inv, *a, &bt, &b)) == SEG_NOT_ASSIGNED) {
1566       rc = sen_memory_exhausted;
1567       goto exit;
1568     }
1569     //  sen_log("b->header.buffer_free=%d size=%d", b->header.buffer_free, size);
1570     if (b->header.buffer_free < size) {
1571       uint32_t _a = *a;
1572       SEN_LOG(sen_log_debug, "flushing! b=%p free=%d, seg(%d)", b, b->header.buffer_free, *a >> W_OF_SEGMENT);
1573       buffer_close(inv, pseg);
1574       if ((rc = buffer_flush(inv, ctx, *a >> W_OF_SEGMENT, h))) { goto exit; }
1575       if (*a != _a) {
1576         SEN_LOG(sen_log_debug, "sen_inv_delete: *a changed %d->%d)", *a, _a);
1577         continue;
1578       }
1579       if ((pseg = buffer_open(inv, *a, &bt, &b)) == SEG_NOT_ASSIGNED) {
1580         rc = sen_memory_exhausted;
1581         goto exit;
1582       }
1583       SEN_LOG(sen_log_debug, "flushed!  b=%p free=%d, seg(%d)", b, b->header.buffer_free, *a >> W_OF_SEGMENT);
1584       if (b->header.buffer_free < size) {
1585         /* todo: must be splitted ? */
1586         SEN_LOG(sen_log_crit, "buffer(%d) is full (%d < %d) in sen_inv_delete",
1587                 *a, b->header.buffer_free, size);
1588         rc = sen_memory_exhausted;
1589         buffer_close(inv, pseg);
1590         goto exit;
1591       }
1592     }
1593
1594     b->header.buffer_free -= size;
1595     br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms]) + b->header.buffer_free);
1596     rc = buffer_put(b, bt, br, bs, u, size);
1597     buffer_close(inv, pseg);
1598     break;
1599   }
1600 exit :
1601   array_unref(inv, key);
1602   if (bs) { SEN_FREE(bs); }
1603   return rc;
1604 }
1605
1606 uint32_t
1607 sen_inv_initial_n_segments(sen_inv *inv)
1608 {
1609   return inv->header->initial_n_segments;
1610 }
1611
1612 #define CHUNK_USED    1
1613 #define BUFFER_USED   2
1614 #define SOLE_DOC_USED 4
1615 #define SOLE_POS_USED 8
1616
1617 sen_inv_cursor *
1618 sen_inv_cursor_open(sen_inv *inv, uint32_t key, int with_pos)
1619 {
1620   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1621   sen_inv_cursor *c  = NULL;
1622   uint32_t pos, *a;
1623   if (inv->v08p) {
1624     return sen_inv_cursor_open08(inv, key);
1625   }
1626   if (!(a = array_at(inv, key))) { return NULL; }
1627   if (!(pos = *a)) { goto exit; }
1628   if (!(c = SEN_MALLOC(sizeof(sen_inv_cursor)))) { goto exit; }
1629   memset(c, 0, sizeof(sen_inv_cursor));
1630   c->inv = inv;
1631   c->iw.ctx = ctx;
1632   c->with_pos = (uint16_t) with_pos;
1633   if (pos & 1) {
1634     c->stat = 0;
1635     c->pb.rid = BIT31_12(pos);
1636     c->pb.tf = 1;
1637     c->pb.score = 0;
1638     if (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON) {
1639       c->pb.sid = 1;
1640       c->pb.pos = BIT11_01(pos);
1641     } else {
1642       c->pb.sid = BIT11_01(pos);
1643       c->pb.pos = sen_sym_pocket_get(inv->lexicon, key);
1644     }
1645   } else {
1646     uint32_t chunk;
1647     buffer_term *bt;
1648     c->pb.rid = 0; c->pb.sid = 0; /* for check */
1649     if ((c->buffer_pseg = buffer_open(inv, pos, &bt, &c->buf)) == SEG_NOT_ASSIGNED) {
1650       SEN_FREE(c);
1651       c = NULL;
1652       goto exit;
1653     }
1654     if (bt->size_in_chunk && (chunk = c->buf->header.chunk) != CHUNK_NOT_ASSIGNED) {
1655       c->cp = sen_io_win_map(inv->chunk, ctx, &c->iw,
1656                              chunk, bt->pos_in_chunk, bt->size_in_chunk, sen_io_rdonly);
1657       if (!c->cp) {
1658         buffer_close(inv, c->buffer_pseg);
1659         SEN_FREE(c);
1660         c = NULL;
1661         goto exit;
1662       }
1663       c->cpe = c->cp + bt->size_in_chunk;
1664       if (bt->size_in_chunk) {
1665         uint32_t o;
1666         SEN_B_DEC(o, c->cp);
1667         c->cpe = c->cpp = c->cp + o;
1668       }
1669       c->flags = 0;
1670       c->pc.rid = 0;
1671       c->pc.sid = 0;
1672     }
1673     c->nextb = bt->pos_in_buffer;
1674     c->stat = CHUNK_USED|BUFFER_USED;
1675   }
1676 exit :
1677   array_unref(inv, key);
1678   return c;
1679 }
1680
1681 #ifdef USE_AIO
1682 sen_inv_cursor *
1683 sen_inv_cursor_openv1(sen_inv *inv, uint32_t key)
1684 {
1685   sen_inv_cursor *c  = NULL;
1686   uint32_t pos, *a = array_at(inv, key);
1687   if (!a) { return NULL; }
1688   if (!(pos = *a)) { goto exit; }
1689   if (!(c = SEN_MALLOC(sizeof(sen_inv_cursor)))) { goto exit; }
1690   memset(c, 0, sizeof(sen_inv_cursor));
1691   c->inv = inv;
1692   if (pos & 1) {
1693     c->stat = 0;
1694     c->pb.rid = BIT31_12(pos);
1695     c->pb.tf = 1;
1696     c->pb.score = 0;
1697     if (inv->lexicon->flags & SEN_INDEX_SHARED_LEXICON) {
1698       c->pb.sid = 1;
1699       c->pb.pos = BIT11_01(pos);
1700     } else {
1701       c->pb.sid = BIT11_01(pos);
1702       c->pb.pos = sen_sym_pocket_get(inv->lexicon, key);
1703     }
1704   } else {
1705     buffer_term *bt;
1706     c->pb.rid = 0; c->pb.sid = 0;
1707     if ((c->buffer_pseg = buffer_open(inv, pos, &bt, &c->buf)) == SEG_NOT_ASSIGNED) {
1708       SEN_FREE(c);
1709       c = NULL;
1710       goto exit;
1711     }
1712     c->iw.io = inv->chunk;
1713     c->iw.mode = sen_io_rdonly;
1714     c->iw.segment = c->buf->header.chunk;
1715     c->iw.offset = bt->pos_in_chunk;
1716     c->iw.size = bt->size_in_chunk;
1717     c->nextb = bt->pos_in_buffer;
1718     c->stat = CHUNK_USED|BUFFER_USED;
1719   }
1720 exit :
1721   array_unref(inv, key);
1722   return c;
1723 }
1724
1725 sen_rc
1726 sen_inv_cursor_openv2(sen_inv_cursor **cursors, int ncursors)
1727 {
1728   sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
1729   sen_rc rc = sen_success;
1730   int i, j = 0;
1731   sen_inv_cursor *c;
1732   sen_io_win **iws = SEN_MALLOC(sizeof(sen_io_win *) * ncursors);
1733   if (!iws) { return sen_memory_exhausted; }
1734   for (i = 0; i < ncursors; i++) {
1735     c = cursors[i];
1736     if (c->stat && c->iw.size && c->iw.segment != CHUNK_NOT_ASSIGNED) {
1737       iws[j++] = &c->iw;
1738     }
1739   }
1740   if (j) { rc = sen_io_win_mapv(iws, ctx, j); }
1741   for (i = 0; i < ncursors; i++) {
1742     c = cursors[i];
1743     if (c->iw.addr) {
1744       c->cp = c->iw.addr + c->iw.diff;
1745       c->cpe = c->cp + c->iw.size;
1746       c->pc.rid = 0;
1747       c->pc.sid = 0;
1748     }
1749   }
1750   SEN_FREE(iws);
1751   return rc;
1752 }
1753 #endif /* USE_AIO */
1754
1755 sen_rc
1756 sen_inv_cursor_next(sen_inv_cursor *c)
1757 {
1758   if (c->inv->v08p) {
1759     return sen_inv_cursor_next08(c);
1760   }
1761   if (c->buf) {
1762     for (;;) {
1763       if (c->stat & CHUNK_USED) {
1764         if (c->cp < c->cpe) {
1765           uint32_t dgap;
1766           if (c->with_pos) { while (c->pc.rest--) { SEN_B_SKIP(c->cpp); } }
1767           if (*c->cp == 0x8c) { c->flags |= 1; c->cp++; } else { c->flags &= ~1; }
1768           if (*c->cp == 0x8d) { c->flags ^= 2; c->cp++; }
1769           if (*c->cp == 0x8e) { c->flags ^= 4; c->cp++; }
1770           SEN_C_DEC(dgap, c->pc.tf, c->cp);
1771           c->pc.rid += dgap;
1772           if (dgap) { c->pc.sid = 0; }
1773           if (c->flags & 4) { SEN_B_DEC(dgap, c->cp); } else { dgap = 0; }
1774           if (c->flags & 3) { SEN_B_DEC(c->pc.score, c->cp); } else { c->pc.score = 0; }
1775           c->pc.sid += dgap + 1;
1776           c->pc.rest = c->pc.tf;
1777           c->pc.pos = 0;
1778         } else {
1779           c->pc.rid = 0;
1780         }
1781       }
1782       if (c->stat & BUFFER_USED) {
1783         if (c->nextb) {
1784           uint32_t lrid = c->pb.rid, lsid = c->pb.sid; /* for check */
1785           buffer_rec *br = BUFFER_REC_AT(c->buf, c->nextb);
1786           c->bp = NEXT_ADDR(br);
1787           SEN_B_DEC(c->pb.rid, c->bp);
1788           SEN_B_DEC(c->pb.sid, c->bp);
1789           if (lrid > c->pb.rid || (lrid == c->pb.rid && lsid >= c->pb.sid)) {
1790             SEN_LOG(sen_log_crit, "brokend!! (%d:%d) -> (%d:%d)", lrid, lsid, c->pb.rid, c->pb.sid);
1791             return sen_abnormal_error;
1792           }
1793           c->nextb = br->step;
1794           SEN_B_DEC(c->pb.tf, c->bp);
1795           if (c->pb.tf & 1) { SEN_B_DEC(c->pb.score, c->bp); } else { c->pb.score = 0; }
1796           c->pb.rest = c->pb.tf >>= 1;
1797           c->pb.pos = 0;
1798         } else {
1799           c->pb.rid = 0;
1800         }
1801       }
1802       if (c->pb.rid) {
1803         if (c->pc.rid) {
1804           if (c->pc.rid < c->pb.rid) {
1805             c->stat = CHUNK_USED;
1806             if (c->pc.tf && c->pc.sid) { c->post = &c->pc; break; }
1807           } else {
1808             if (c->pb.rid < c->pc.rid) {
1809               c->stat = BUFFER_USED;
1810               if (c->pb.tf && c->pb.sid) { c->post = &c->pb; break; }
1811             } else {
1812               if (c->pb.sid) {
1813                 if (c->pc.sid < c->pb.sid) {
1814                   c->stat = CHUNK_USED;
1815                   if (c->pc.tf && c->pc.sid) { c->post = &c->pc; break; }
1816                 } else {
1817                   c->stat = BUFFER_USED;
1818                   if (c->pb.sid == c->pc.sid) { c->stat |= CHUNK_USED; }
1819                   if (c->pb.tf) { c->post = &c->pb; break; }
1820                 }
1821               } else {
1822                 c->stat = CHUNK_USED;
1823               }
1824             }
1825           }
1826         } else {
1827           c->stat = BUFFER_USED;
1828           if (c->pb.tf && c->pb.sid) { c->post = &c->pb; break; }
1829         }
1830       } else {
1831         if (c->pc.rid) {
1832           c->stat = CHUNK_USED;
1833           if (c->pc.tf && c->pc.sid) { c->post = &c->pc; break; }
1834         } else {
1835           c->post = NULL;
1836           return sen_abnormal_error;
1837         }
1838       }
1839     }
1840   } else {
1841     if (c->stat & SOLE_DOC_USED) {
1842       c->post = NULL;
1843       return sen_abnormal_error;
1844     } else {
1845       c->post = &c->pb;
1846       c->stat |= SOLE_DOC_USED;
1847     }
1848   }
1849   return sen_success;
1850 }
1851
1852 sen_rc
1853 sen_inv_cursor_next_pos(sen_inv_cursor *c)
1854 {
1855   uint32_t gap;
1856   sen_rc rc = sen_success;
1857   if (c->inv->v08p) {
1858     return sen_inv_cursor_next_pos08(c);
1859   }
1860   if (c->with_pos) {
1861     if (c->buf) {
1862       if (c->post == &c->pc) {
1863         if (c->pc.rest) {
1864           c->pc.rest--;
1865           SEN_B_DEC(gap, c->cpp);
1866           c->pc.pos += gap;
1867         } else {
1868           rc = sen_abnormal_error;
1869         }
1870       } else if (c->post == &c->pb) {
1871         if (c->pb.rest) {
1872           c->pb.rest--;
1873           SEN_B_DEC(gap, c->bp);
1874           c->pb.pos += gap;
1875         } else {
1876           rc = sen_abnormal_error;
1877         }
1878       } else {
1879         rc = sen_abnormal_error;
1880       }
1881     } else {
1882       if (c->stat & SOLE_POS_USED) {
1883         rc = sen_abnormal_error;
1884       } else {
1885         c->stat |= SOLE_POS_USED;
1886       }
1887     }
1888   }
1889   return rc;
1890 }
1891
1892 sen_rc
1893 sen_inv_cursor_close(sen_inv_cursor *c)
1894 {
1895   sen_ctx *ctx = c->iw.ctx;
1896   if (c->inv->v08p) {
1897     return sen_inv_cursor_close08(c);
1898   }
1899   if (!c) { return sen_invalid_argument; }
1900   if (c->cp) { sen_io_win_unmap(&c->iw); }
1901   if (c->buf) { buffer_close(c->inv, c->buffer_pseg); }
1902   SEN_FREE(c);
1903   return sen_success;
1904 }
1905
1906 uint32_t
1907 sen_inv_estimate_size(sen_inv *inv, uint32_t key)
1908 {
1909   uint32_t res, pos, *a;
1910   if (inv->v08p) {
1911     return sen_inv_estimate_size08(inv, key);
1912   }
1913   a = array_at(inv, key);
1914   if (!a) { return 0; }
1915   if ((pos = *a)) {
1916     if (pos & 1) {
1917       res = 1;
1918     } else {
1919       buffer *buf;
1920       uint16_t pseg;
1921       buffer_term *bt;
1922       if ((pseg = buffer_open(inv, pos, &bt, &buf)) == SEG_NOT_ASSIGNED) {
1923         res = 0;
1924       } else {
1925         res = (bt->size_in_chunk >> 1) + bt->size_in_buffer + 2;
1926         buffer_close(inv, pseg);
1927       }
1928     }
1929   } else {
1930     res = 0;
1931   }
1932   array_unref(inv, key);
1933   return res;
1934 }
1935
1936 int
1937 sen_inv_entry_info(sen_inv *inv, unsigned key, unsigned *a, unsigned *pocket,
1938                    unsigned *chunk, unsigned *chunk_size, unsigned *buffer_free,
1939                    unsigned *nterms, unsigned *nterms_void, unsigned *tid,
1940                    unsigned *size_in_chunk, unsigned *pos_in_chunk,
1941                    unsigned *size_in_buffer, unsigned *pos_in_buffer)
1942 {
1943   buffer *b;
1944   buffer_term *bt;
1945   uint32_t *ap;
1946   uint16_t pseg;
1947   ERRCLR(NULL);
1948   if (inv->v08p) {
1949     return sen_inv_entry_info08(inv, key, a, pocket,
1950                                 chunk, chunk_size, buffer_free,
1951                                 nterms, nterms_void, tid,
1952                                 size_in_chunk, pos_in_chunk,
1953                                 size_in_buffer, pos_in_buffer);
1954   }
1955   ap = array_at(inv, key);
1956   *pocket = sen_sym_pocket_get(inv->lexicon, key);
1957   if (!ap) { return 0; }
1958   *a = *ap;
1959   array_unref(inv, key);
1960   if (!*a) { return 1; }
1961   if (*a & 1) { return 2; }
1962   if ((pseg = buffer_open(inv, *a, &bt, &b)) == SEG_NOT_ASSIGNED) { return 3; }
1963   *chunk = b->header.chunk;
1964   *chunk_size = b->header.chunk_size;
1965   *buffer_free = b->header.buffer_free;
1966   *nterms = b->header.nterms;
1967   *tid = bt->tid;
1968   *size_in_chunk = bt->size_in_chunk;
1969   *pos_in_chunk = bt->pos_in_chunk;
1970   *size_in_buffer = bt->size_in_buffer;
1971   *pos_in_buffer = bt->pos_in_buffer;
1972   buffer_close(inv, pseg);
1973   return 4;
1974 }
1975
1976 const char *
1977 sen_inv_path(sen_inv *inv)
1978 {
1979   return sen_io_path(inv->seg);
1980 }
1981
1982 uint32_t
1983 sen_inv_max_section(sen_inv *inv)
1984 {
1985   if (inv->v08p) {
1986     return SEN_SYM_MAX_ID;
1987   }
1988   return inv->header->smax;
1989 }