1 /* This file is part of the Zebra server.
2 Copyright (C) 2004-2013 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
21 \brief indexes records and extract tokens for indexing and sorting
43 #include <yaz/snprintf.h>
45 static int log_level_extract = 0;
46 static int log_level_details = 0;
47 static int log_level_initialized = 0;
49 /* 1 if we use eliminitate identical delete/insert keys */
50 /* eventually this the 0-case code will be removed */
54 static void extract_flush_record_keys2(ZebraHandle zh, zint sysno,
55 zebra_rec_keys_t ins_keys,
57 zebra_rec_keys_t del_keys,
60 static void extract_flush_record_keys(ZebraHandle zh, zint sysno,
62 zebra_rec_keys_t reckeys,
66 static void zebra_init_log_level(void)
68 if (!log_level_initialized)
70 log_level_initialized = 1;
72 log_level_extract = yaz_log_module_level("extract");
73 log_level_details = yaz_log_module_level("indexdetails");
77 static WRBUF wrbuf_hex_str(const char *cstr)
80 WRBUF w = wrbuf_alloc();
81 for (i = 0; cstr[i]; i++)
83 if (cstr[i] < ' ' || cstr[i] > 126)
84 wrbuf_printf(w, "\\%02X", cstr[i] & 0xff);
86 wrbuf_putc(w, cstr[i]);
92 static void extract_flush_sort_keys(ZebraHandle zh, zint sysno,
93 int cmd, zebra_rec_keys_t skp);
94 static void extract_schema_add(struct recExtractCtrl *p, Odr_oid *oid);
95 static void extract_token_add(RecWord *p);
97 static void check_log_limit(ZebraHandle zh)
99 if (zh->records_processed + zh->records_skipped == zh->m_file_verbose_limit)
101 yaz_log(YLOG_LOG, "More than %d file log entries. Omitting rest",
102 zh->m_file_verbose_limit);
106 static void logRecord(ZebraHandle zh)
109 ++zh->records_processed;
110 if (!(zh->records_processed % 1000))
112 yaz_log(YLOG_LOG, "Records: "ZINT_FORMAT" i/u/d "
113 ZINT_FORMAT"/"ZINT_FORMAT"/"ZINT_FORMAT,
114 zh->records_processed, zh->records_inserted,
115 zh->records_updated, zh->records_deleted);
119 static void init_extractCtrl(ZebraHandle zh, struct recExtractCtrl *ctrl)
121 ctrl->flagShowRecords = !zh->m_flag_rw;
125 static void extract_add_index_string(RecWord *p,
126 zinfo_index_category_t cat,
127 const char *str, int length);
129 static void extract_set_store_data_prepare(struct recExtractCtrl *p);
131 static void extract_init(struct recExtractCtrl *p, RecWord *w)
134 w->index_name = "any";
142 struct snip_rec_info {
144 zebra_snippets *snippets;
147 static int parse_complete_field(RecWord *p, zebra_map_t zm,
150 const char *b = p->term_buf;
151 const char **map = 0;
152 int i = 0, remain = p->term_len;
155 map = zebra_maps_input(zm, &b, remain, 1);
156 while (remain > 0 && i < IT_MAX_WORD)
158 while (map && *map && **map == *CHR_SPACE)
160 remain = p->term_len - (b - p->term_buf);
164 int first = i ? 0 : 1; /* first position */
165 map = zebra_maps_input(zm, &b, remain, first);
173 if (i && i < IT_MAX_WORD)
174 buf[i++] = *CHR_SPACE;
175 while (map && *map && **map != *CHR_SPACE)
177 const char *cp = *map;
179 if (**map == *CHR_CUT)
185 if (i >= IT_MAX_WORD)
187 while (i < IT_MAX_WORD && *cp)
190 remain = p->term_len - (b - p->term_buf);
193 map = zebra_maps_input(zm, &b, remain, 0);
202 static void snippet_add_complete_field(RecWord *p, int ord,
205 struct snip_rec_info *h = p->extractCtrl->handle;
206 char buf[IT_MAX_WORD+1];
207 int i = parse_complete_field(p, zm, buf);
212 if (p->term_len && p->term_buf && zebra_maps_is_index(zm))
213 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
214 p->term_buf, p->term_len);
218 static void snippet_add_incomplete_field(RecWord *p, int ord, zebra_map_t zm)
220 struct snip_rec_info *h = p->extractCtrl->handle;
221 const char *b = p->term_buf;
222 int remain = p->term_len;
224 const char **map = 0;
225 const char *start = b;
226 const char *last = b;
229 map = zebra_maps_input(zm, &b, remain, 0);
236 while (map && *map && **map == *CHR_SPACE)
238 remain = p->term_len - (b - p->term_buf);
241 map = zebra_maps_input(zm, &b, remain, 0);
247 if (start != last && zebra_maps_is_index(zm))
249 zebra_snippets_appendn(h->snippets, p->seqno, 1, ord,
250 start, last - start);
253 while (map && *map && **map != *CHR_SPACE)
255 remain = p->term_len - (b - p->term_buf);
258 map = zebra_maps_input(zm, &b, remain, 0);
268 if (zebra_maps_is_first_in_field(zm))
270 /* first in field marker */
274 if (start != last && zebra_maps_is_index(zm))
275 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
276 start, last - start);
283 static void snippet_add_icu(RecWord *p, int ord, zebra_map_t zm)
285 struct snip_rec_info *h = p->extractCtrl->handle;
287 const char *res_buf = 0;
290 const char *display_buf = 0;
291 size_t display_len = 0;
293 zebra_map_tokenize_start(zm, p->term_buf, p->term_len);
294 while (zebra_map_tokenize_next(zm, &res_buf, &res_len,
295 &display_buf, &display_len))
297 if (zebra_maps_is_index(zm))
298 zebra_snippets_appendn(h->snippets, p->seqno, 0, ord,
299 display_buf, display_len);
304 static void snippet_token_add(RecWord *p)
306 struct snip_rec_info *h = p->extractCtrl->handle;
307 ZebraHandle zh = h->zh;
308 zebra_map_t zm = zebra_map_get_or_add(zh->reg->zebra_maps, p->index_type);
312 ZebraExplainInfo zei = zh->reg->zei;
313 int ch = zebraExplain_lookup_attr_str(
314 zei, zinfo_index_category_index, p->index_type, p->index_name);
316 if (zebra_maps_is_icu(zm))
317 snippet_add_icu(p, ch, zm);
320 if (zebra_maps_is_complete(zm))
321 snippet_add_complete_field(p, ch, zm);
323 snippet_add_incomplete_field(p, ch, zm);
328 static void snippet_schema_add(
329 struct recExtractCtrl *p, Odr_oid *oid)
334 void extract_snippet(ZebraHandle zh, zebra_snippets *sn,
335 struct ZebraRecStream *stream,
336 RecType rt, void *recTypeClientData)
338 struct recExtractCtrl extractCtrl;
339 struct snip_rec_info info;
341 extractCtrl.stream = stream;
342 extractCtrl.first_record = 1;
343 extractCtrl.init = extract_init;
344 extractCtrl.tokenAdd = snippet_token_add;
345 extractCtrl.schemaAdd = snippet_schema_add;
349 extractCtrl.dh = zh->reg->dh;
353 extractCtrl.handle = &info;
354 extractCtrl.match_criteria[0] = '\0';
355 extractCtrl.staticrank = 0;
356 extractCtrl.action = action_insert;
358 init_extractCtrl(zh, &extractCtrl);
360 extractCtrl.setStoreData = 0;
362 (*rt->extract)(recTypeClientData, &extractCtrl);
365 static void searchRecordKey(ZebraHandle zh,
366 zebra_rec_keys_t reckeys,
367 const char *index_name,
368 const char **ws, int ws_length)
372 zinfo_index_category_t cat = zinfo_index_category_index;
374 for (i = 0; i<ws_length; i++)
378 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "0", index_name);
380 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "p", index_name);
382 ch = zebraExplain_lookup_attr_str(zh->reg->zei, cat, "w", index_name);
387 if (zebra_rec_keys_rewind(reckeys))
394 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
396 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
398 seqno = key.mem[key.len-1];
400 if (key.mem[0] == ch)
406 woff = seqno - startSeq;
407 if (woff >= 0 && woff < ws_length)
414 #define FILE_MATCH_BLANK "\t "
416 static char *get_match_from_spec(ZebraHandle zh,
417 zebra_rec_keys_t reckeys,
418 const char *fname, const char *spec)
420 static char dstBuf[2048]; /* static here ??? */
422 const char *s = spec;
426 for (; *s && strchr(FILE_MATCH_BLANK, *s); s++)
433 char attset_str[64], attname_str[64];
437 for (s++; strchr(FILE_MATCH_BLANK, *s); s++)
439 for (i = 0; *s && *s != ',' && *s != ')' &&
440 !strchr(FILE_MATCH_BLANK, *s); s++)
441 if (i+1 < sizeof(attset_str))
442 attset_str[i++] = *s;
443 attset_str[i] = '\0';
445 for (; strchr(FILE_MATCH_BLANK, *s); s++)
448 strcpy(attname_str, attset_str);
451 for (s++; strchr(FILE_MATCH_BLANK, *s); s++)
453 for (i = 0; *s && *s != ')' &&
454 !strchr(FILE_MATCH_BLANK, *s); s++)
455 if (i+1 < sizeof(attname_str))
456 attname_str[i++] = *s;
457 attname_str[i] = '\0';
461 yaz_log(YLOG_WARN, "Missing ) in match criteria %s in group %s",
462 spec, zh->m_group ? zh->m_group : "none");
467 searchRecordKey(zh, reckeys, attname_str, ws, 32);
468 if (0) /* for debugging */
470 for (i = 0; i<32; i++)
474 WRBUF w = wrbuf_hex_str(ws[i]);
475 yaz_log(YLOG_LOG, "ws[%d] = %s", i, wrbuf_cstr(w));
481 for (i = 0; i<32; i++)
490 dst += strlen(ws[i]);
494 yaz_log(YLOG_WARN, "Record didn't contain match"
495 " fields in (%s,%s)", attset_str, attname_str);
503 const char *spec_src = NULL;
504 const char *s1 = ++s;
505 while (*s1 && !strchr(FILE_MATCH_BLANK, *s1))
509 if (spec_len > sizeof(special)-1)
510 spec_len = sizeof(special)-1;
511 memcpy(special, s, spec_len);
512 special[spec_len] = '\0';
515 if (!strcmp(special, "group"))
516 spec_src = zh->m_group;
517 else if (!strcmp(special, "database"))
518 spec_src = zh->basenames[0];
519 else if (!strcmp(special, "filename")) {
522 else if (!strcmp(special, "type"))
523 spec_src = zh->m_record_type;
528 strcpy(dst, spec_src);
529 dst += strlen(spec_src);
532 else if (*s == '\"' || *s == '\'')
534 int stopMarker = *s++;
538 while (*s && *s != stopMarker)
540 if (i+1 < sizeof(tmpString))
541 tmpString[i++] = *s++;
546 strcpy(dst, tmpString);
547 dst += strlen(tmpString);
551 yaz_log(YLOG_WARN, "Syntax error in match criteria %s in group %s",
552 spec, zh->m_group ? zh->m_group : "none");
559 yaz_log(YLOG_WARN, "No match criteria for record %s in group %s",
560 fname, zh->m_group ? zh->m_group : "none");
565 if (0) /* for debugging */
567 WRBUF w = wrbuf_hex_str(dstBuf);
568 yaz_log(YLOG_LOG, "get_match_from_spec %s", wrbuf_cstr(w));
575 struct recordLogInfo {
578 struct recordGroup *rGroup;
581 /** \brief add the always-matches index entry and map to real record ID
582 \param ctrl record control
583 \param record_id custom record ID
584 \param sysno system record ID
586 This function serves two purposes.. It adds the always matches
587 entry and makes a pointer from the custom record ID (if defined)
588 back to the system record ID (sysno)
589 See zebra_recid_to_sysno .
591 static void all_matches_add(struct recExtractCtrl *ctrl, zint record_id,
595 extract_init(ctrl, &word);
596 word.record_id = record_id;
597 /* we use the seqno as placeholder for a way to get back to
598 record database from _ALLRECORDS.. This is used if a custom
599 RECORD was defined */
601 word.index_name = "_ALLRECORDS";
602 word.index_type = "w";
604 extract_add_index_string(&word, zinfo_index_category_alwaysmatches,
608 /* forward declaration */
609 ZEBRA_RES zebra_extract_records_stream(ZebraHandle zh,
610 struct ZebraRecStream *stream,
611 enum zebra_recctrl_action_t action,
612 const char *recordType,
614 const char *match_criteria,
617 void *recTypeClientData);
620 ZEBRA_RES zebra_extract_file(ZebraHandle zh, zint *sysno, const char *fname,
621 enum zebra_recctrl_action_t action)
623 ZEBRA_RES r = ZEBRA_OK;
628 const char *original_record_type = 0;
630 void *recTypeClientData;
631 struct ZebraRecStream stream, *streamp;
633 zebra_init_log_level();
635 if (!zh->m_group || !*zh->m_group)
638 sprintf(gprefix, "%s.", zh->m_group);
640 yaz_log(log_level_extract, "zebra_extract_file %s", fname);
642 /* determine file extension */
644 for (i = strlen(fname); --i >= 0; )
647 else if (fname[i] == '.')
649 strcpy(ext, fname+i+1);
652 /* determine file type - depending on extension */
653 original_record_type = zh->m_record_type;
654 if (!zh->m_record_type)
656 sprintf(ext_res, "%srecordType.%s", gprefix, ext);
657 zh->m_record_type = res_get(zh->res, ext_res);
659 if (!zh->m_record_type)
662 if (zh->records_processed + zh->records_skipped
663 < zh->m_file_verbose_limit)
664 yaz_log(YLOG_LOG, "? %s", fname);
665 zh->records_skipped++;
668 /* determine match criteria */
669 if (!zh->m_record_id)
671 sprintf(ext_res, "%srecordId.%s", gprefix, ext);
672 zh->m_record_id = res_get(zh->res, ext_res);
676 recType_byName(zh->reg->recTypes, zh->res, zh->m_record_type,
677 &recTypeClientData)))
679 yaz_log(YLOG_WARN, "No such record type: %s", zh->m_record_type);
683 switch(recType->version)
688 yaz_log(YLOG_WARN, "Bad filter version: %s", zh->m_record_type);
690 if (sysno && (action == action_delete || action == action_a_delete))
698 if (zh->path_reg && !yaz_is_abspath(fname))
700 strcpy(full_rep, zh->path_reg);
701 strcat(full_rep, "/");
702 strcat(full_rep, fname);
705 strcpy(full_rep, fname);
707 if ((fd = open(full_rep, O_BINARY|O_RDONLY)) == -1)
709 yaz_log(YLOG_WARN|YLOG_ERRNO, "open %s", full_rep);
710 zh->m_record_type = original_record_type;
714 zebra_create_stream_fd(streamp, fd, 0);
716 r = zebra_extract_records_stream(zh, streamp,
720 0, /*match_criteria */
722 recType, recTypeClientData);
724 stream.destroy(streamp);
725 zh->m_record_type = original_record_type;
730 If sysno is provided, then it's used to identify the reocord.
731 If not, and match_criteria is provided, then sysno is guessed
732 If not, and a record is provided, then sysno is got from there
736 ZEBRA_RES zebra_buffer_extract_record(ZebraHandle zh,
737 const char *buf, size_t buf_size,
738 enum zebra_recctrl_action_t action,
739 const char *recordType,
741 const char *match_criteria,
744 struct ZebraRecStream stream;
749 if (recordType && *recordType)
751 yaz_log(log_level_extract,
752 "Record type explicitly specified: %s", recordType);
753 recType = recType_byName(zh->reg->recTypes, zh->res, recordType,
758 if (!(zh->m_record_type))
760 yaz_log(YLOG_WARN, "No such record type defined");
763 yaz_log(log_level_extract, "Get record type from rgroup: %s",
765 recType = recType_byName(zh->reg->recTypes, zh->res,
766 zh->m_record_type, &clientData);
767 recordType = zh->m_record_type;
772 yaz_log(YLOG_WARN, "No such record type: %s", recordType);
776 zebra_create_stream_mem(&stream, buf, buf_size);
778 res = zebra_extract_records_stream(zh, &stream,
784 recType, clientData);
785 stream.destroy(&stream);
789 static ZEBRA_RES zebra_extract_record_stream(ZebraHandle zh,
790 struct ZebraRecStream *stream,
791 enum zebra_recctrl_action_t action,
792 const char *recordType,
794 const char *match_criteria,
797 void *recTypeClientData,
802 RecordAttr *recordAttr;
803 struct recExtractCtrl extractCtrl;
805 const char *matchStr = 0;
807 off_t start_offset = 0, end_offset = 0;
808 const char *pr_fname = fname; /* filename to print .. */
809 int show_progress = zh->records_processed + zh->records_skipped
810 < zh->m_file_verbose_limit ? 1:0;
812 zebra_init_log_level();
815 pr_fname = "<no file>"; /* make it printable if file is omitted */
817 zebra_rec_keys_reset(zh->reg->keys);
818 zebra_rec_keys_reset(zh->reg->sortKeys);
820 if (zebraExplain_curDatabase(zh->reg->zei, zh->basenames[0]))
822 if (zebraExplain_newDatabase(zh->reg->zei, zh->basenames[0],
823 zh->m_explain_database))
829 off_t null_offset = 0;
830 extractCtrl.stream = stream;
832 start_offset = stream->tellf(stream);
834 extractCtrl.first_record = start_offset ? 0 : 1;
836 stream->endf(stream, &null_offset);;
838 extractCtrl.init = extract_init;
839 extractCtrl.tokenAdd = extract_token_add;
840 extractCtrl.schemaAdd = extract_schema_add;
841 extractCtrl.dh = zh->reg->dh;
842 extractCtrl.handle = zh;
843 extractCtrl.match_criteria[0] = '\0';
844 extractCtrl.staticrank = 0;
845 extractCtrl.action = action;
847 init_extractCtrl(zh, &extractCtrl);
849 extract_set_store_data_prepare(&extractCtrl);
851 r = (*recType->extract)(recTypeClientData, &extractCtrl);
853 if (action == action_update)
855 action = extractCtrl.action;
860 case RECCTRL_EXTRACT_EOF:
862 case RECCTRL_EXTRACT_ERROR_GENERIC:
863 /* error occured during extraction ... */
864 yaz_log(YLOG_WARN, "extract error: generic");
866 case RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER:
867 /* error occured during extraction ... */
868 yaz_log(YLOG_WARN, "extract error: no such filter");
870 case RECCTRL_EXTRACT_SKIP:
872 yaz_log(YLOG_LOG, "skip %s %s " ZINT_FORMAT,
873 recordType, pr_fname, (zint) start_offset);
876 end_offset = stream->endf(stream, 0);
878 stream->seekf(stream, end_offset);
881 case RECCTRL_EXTRACT_OK:
884 yaz_log(YLOG_WARN, "extract error: unknown error: %d", r);
887 end_offset = stream->endf(stream, 0);
889 stream->seekf(stream, end_offset);
891 end_offset = stream->tellf(stream);
893 if (extractCtrl.match_criteria[0])
894 match_criteria = extractCtrl.match_criteria;
899 if (zh->m_flag_rw == 0)
901 yaz_log(YLOG_LOG, "test %s %s " ZINT_FORMAT, recordType,
902 pr_fname, (zint) start_offset);
903 /* test mode .. Do not perform match */
911 if (match_criteria && *match_criteria)
912 matchStr = match_criteria;
915 if (zh->m_record_id && *zh->m_record_id)
917 matchStr = get_match_from_spec(zh, zh->reg->keys, pr_fname,
921 yaz_log(YLOG_LOG, "error %s %s " ZINT_FORMAT, recordType,
922 pr_fname, (zint) start_offset);
927 WRBUF w = wrbuf_alloc();
929 for (i = 0; i < strlen(matchStr); i++)
931 wrbuf_printf(w, "%02X", matchStr[i] & 0xff);
933 yaz_log(YLOG_LOG, "Got match %s", wrbuf_cstr(w));
940 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
941 char *rinfo = dict_lookup_ord(zh->reg->matchDict, db_ord,
945 if (log_level_extract)
947 WRBUF w = wrbuf_hex_str(matchStr);
948 yaz_log(log_level_extract, "matchStr: %s", wrbuf_cstr(w));
953 assert(*rinfo == sizeof(*sysno));
954 memcpy(sysno, rinfo+1, sizeof(*sysno));
961 /* new record AKA does not exist already */
962 if (action == action_delete)
964 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
965 pr_fname, (zint) start_offset);
966 yaz_log(YLOG_WARN, "cannot delete record above (seems new)");
969 else if (action == action_a_delete)
972 yaz_log(YLOG_LOG, "adelete %s %s " ZINT_FORMAT, recordType,
973 pr_fname, (zint) start_offset);
976 else if (action == action_replace)
978 yaz_log(YLOG_LOG, "update %s %s " ZINT_FORMAT, recordType,
979 pr_fname, (zint) start_offset);
980 yaz_log(YLOG_WARN, "cannot update record above (seems new)");
984 yaz_log(YLOG_LOG, "add %s %s " ZINT_FORMAT, recordType, pr_fname,
985 (zint) start_offset);
986 rec = rec_new(zh->reg->records);
993 all_matches_add(&extractCtrl,
994 zebra_rec_keys_get_custom_record_id(zh->reg->keys),
999 recordAttr = rec_init_attr(zh->reg->zei, rec);
1000 if (extractCtrl.staticrank < 0)
1002 yaz_log(YLOG_WARN, "Negative staticrank for record. Set to 0");
1003 extractCtrl.staticrank = 0;
1008 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1009 dict_insert_ord(zh->reg->matchDict, db_ord, matchStr,
1010 sizeof(*sysno), sysno);
1013 extract_flush_sort_keys(zh, *sysno, 1, zh->reg->sortKeys);
1015 extract_flush_record_keys2(zh, *sysno,
1016 zh->reg->keys, extractCtrl.staticrank,
1017 0, recordAttr->staticrank);
1019 extract_flush_record_keys(zh, *sysno, 1, zh->reg->keys,
1020 extractCtrl.staticrank);
1022 recordAttr->staticrank = extractCtrl.staticrank;
1023 zh->records_inserted++;
1027 /* record already exists */
1028 zebra_rec_keys_t delkeys = zebra_rec_keys_open();
1029 zebra_rec_keys_t sortKeys = zebra_rec_keys_open();
1030 if (action == action_insert)
1032 yaz_log(YLOG_LOG, "skipped %s %s " ZINT_FORMAT,
1033 recordType, pr_fname, (zint) start_offset);
1038 rec = rec_get(zh->reg->records, *sysno);
1043 all_matches_add(&extractCtrl,
1044 zebra_rec_keys_get_custom_record_id(zh->reg->keys),
1048 recordAttr = rec_init_attr(zh->reg->zei, rec);
1050 /* decrease total size */
1051 zebraExplain_recordBytesIncrement(zh->reg->zei,
1052 - recordAttr->recordSize);
1054 zebra_rec_keys_set_buf(delkeys,
1055 rec->info[recInfo_delKeys],
1056 rec->size[recInfo_delKeys],
1058 zebra_rec_keys_set_buf(sortKeys,
1059 rec->info[recInfo_sortKeys],
1060 rec->size[recInfo_sortKeys],
1063 extract_flush_sort_keys(zh, *sysno, 0, sortKeys);
1065 extract_flush_record_keys(zh, *sysno, 0, delkeys,
1066 recordAttr->staticrank);
1068 if (action == action_delete || action == action_a_delete)
1070 /* record going to be deleted */
1072 extract_flush_record_keys2(zh, *sysno, 0, recordAttr->staticrank,
1073 delkeys, recordAttr->staticrank);
1075 if (zebra_rec_keys_empty(delkeys))
1077 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
1078 pr_fname, (zint) start_offset);
1079 yaz_log(YLOG_WARN, "cannot delete file above, "
1080 "storeKeys false (3)");
1085 yaz_log(YLOG_LOG, "delete %s %s " ZINT_FORMAT, recordType,
1086 pr_fname, (zint) start_offset);
1087 zh->records_deleted++;
1090 int db_ord = zebraExplain_get_database_ord(zh->reg->zei);
1091 dict_delete_ord(zh->reg->matchDict, db_ord, matchStr);
1093 rec_del(zh->reg->records, &rec);
1095 zebra_rec_keys_close(delkeys);
1096 zebra_rec_keys_close(sortKeys);
1102 { /* update or special_update */
1104 yaz_log(YLOG_LOG, "update %s %s " ZINT_FORMAT, recordType,
1105 pr_fname, (zint) start_offset);
1106 extract_flush_sort_keys(zh, *sysno, 1, zh->reg->sortKeys);
1109 extract_flush_record_keys2(zh, *sysno,
1110 zh->reg->keys, extractCtrl.staticrank,
1111 delkeys, recordAttr->staticrank);
1113 extract_flush_record_keys(zh, *sysno, 1,
1114 zh->reg->keys, extractCtrl.staticrank);
1116 recordAttr->staticrank = extractCtrl.staticrank;
1117 zh->records_updated++;
1119 zebra_rec_keys_close(delkeys);
1120 zebra_rec_keys_close(sortKeys);
1122 /* update file type */
1123 xfree(rec->info[recInfo_fileType]);
1124 rec->info[recInfo_fileType] =
1125 rec_strdup(recordType, &rec->size[recInfo_fileType]);
1127 /* update filename */
1128 xfree(rec->info[recInfo_filename]);
1129 rec->info[recInfo_filename] =
1130 rec_strdup(fname, &rec->size[recInfo_filename]);
1132 /* update delete keys */
1133 xfree(rec->info[recInfo_delKeys]);
1134 if (!zebra_rec_keys_empty(zh->reg->keys) && zh->m_store_keys == 1)
1136 zebra_rec_keys_get_buf(zh->reg->keys,
1137 &rec->info[recInfo_delKeys],
1138 &rec->size[recInfo_delKeys]);
1142 rec->info[recInfo_delKeys] = NULL;
1143 rec->size[recInfo_delKeys] = 0;
1145 /* update sort keys */
1146 xfree(rec->info[recInfo_sortKeys]);
1148 zebra_rec_keys_get_buf(zh->reg->sortKeys,
1149 &rec->info[recInfo_sortKeys],
1150 &rec->size[recInfo_sortKeys]);
1154 recordAttr->recordSize = end_offset - start_offset;
1155 zebraExplain_recordBytesIncrement(zh->reg->zei,
1156 recordAttr->recordSize);
1159 /* set run-number for this record */
1160 recordAttr->runNumber =
1161 zebraExplain_runNumberIncrement(zh->reg->zei, 0);
1163 /* update store data */
1164 xfree(rec->info[recInfo_storeData]);
1166 /* update store data */
1167 if (zh->store_data_buf)
1169 rec->size[recInfo_storeData] = zh->store_data_size;
1170 rec->info[recInfo_storeData] = zh->store_data_buf;
1171 zh->store_data_buf = 0;
1172 recordAttr->recordSize = zh->store_data_size;
1174 else if (zh->m_store_data)
1176 off_t cur_offset = stream->tellf(stream);
1178 rec->size[recInfo_storeData] = recordAttr->recordSize;
1179 rec->info[recInfo_storeData] = (char *)
1180 xmalloc(recordAttr->recordSize);
1181 stream->seekf(stream, start_offset);
1182 stream->readf(stream, rec->info[recInfo_storeData],
1183 recordAttr->recordSize);
1184 stream->seekf(stream, cur_offset);
1188 rec->info[recInfo_storeData] = NULL;
1189 rec->size[recInfo_storeData] = 0;
1191 /* update database name */
1192 xfree(rec->info[recInfo_databaseName]);
1193 rec->info[recInfo_databaseName] =
1194 rec_strdup(zh->basenames[0], &rec->size[recInfo_databaseName]);
1197 recordAttr->recordOffset = start_offset;
1199 /* commit this record */
1200 rec_put(zh->reg->records, &rec);
1205 /** \brief extracts records from stream
1206 \param zh Zebra Handle
1207 \param stream stream that we read from
1208 \param action (action_insert, action_replace, action_delete, ..)
1209 \param recordType Record filter type "grs.xml", etc.
1210 \param sysno pointer to sysno if already known; NULL otherwise
1211 \param match_criteria (NULL if not already given)
1212 \param fname filename that we read from (for logging purposes only)
1213 \param recType record type
1214 \param recTypeClientData client data for record type
1215 \returns ZEBRA_OK for success; ZEBRA_FAIL for failure
1217 ZEBRA_RES zebra_extract_records_stream(ZebraHandle zh,
1218 struct ZebraRecStream *stream,
1219 enum zebra_recctrl_action_t action,
1220 const char *recordType,
1222 const char *match_criteria,
1225 void *recTypeClientData)
1227 ZEBRA_RES res = ZEBRA_OK;
1231 res = zebra_extract_record_stream(zh, stream,
1237 recType, recTypeClientData, &more);
1243 if (res != ZEBRA_OK)
1251 ZEBRA_RES zebra_extract_explain(void *handle, Record rec, data1_node *n)
1253 ZebraHandle zh = (ZebraHandle) handle;
1254 struct recExtractCtrl extractCtrl;
1256 if (zebraExplain_curDatabase(zh->reg->zei,
1257 rec->info[recInfo_databaseName]))
1260 if (zebraExplain_newDatabase(zh->reg->zei,
1261 rec->info[recInfo_databaseName], 0))
1265 zebra_rec_keys_reset(zh->reg->keys);
1266 zebra_rec_keys_reset(zh->reg->sortKeys);
1268 extractCtrl.init = extract_init;
1269 extractCtrl.tokenAdd = extract_token_add;
1270 extractCtrl.schemaAdd = extract_schema_add;
1271 extractCtrl.dh = zh->reg->dh;
1273 init_extractCtrl(zh, &extractCtrl);
1275 extractCtrl.flagShowRecords = 0;
1276 extractCtrl.match_criteria[0] = '\0';
1277 extractCtrl.staticrank = 0;
1278 extractCtrl.action = action_update;
1280 extractCtrl.handle = handle;
1281 extractCtrl.first_record = 1;
1283 extract_set_store_data_prepare(&extractCtrl);
1286 grs_extract_tree(&extractCtrl, n);
1288 if (rec->size[recInfo_delKeys])
1290 zebra_rec_keys_t delkeys = zebra_rec_keys_open();
1292 zebra_rec_keys_t sortkeys = zebra_rec_keys_open();
1294 zebra_rec_keys_set_buf(delkeys, rec->info[recInfo_delKeys],
1295 rec->size[recInfo_delKeys],
1298 extract_flush_record_keys2(zh, rec->sysno,
1299 zh->reg->keys, 0, delkeys, 0);
1301 extract_flush_record_keys(zh, rec->sysno, 0, delkeys, 0);
1302 extract_flush_record_keys(zh, rec->sysno, 1, zh->reg->keys, 0);
1304 zebra_rec_keys_close(delkeys);
1306 zebra_rec_keys_set_buf(sortkeys, rec->info[recInfo_sortKeys],
1307 rec->size[recInfo_sortKeys],
1310 extract_flush_sort_keys(zh, rec->sysno, 0, sortkeys);
1311 zebra_rec_keys_close(sortkeys);
1316 extract_flush_record_keys2(zh, rec->sysno, zh->reg->keys, 0, 0, 0);
1318 extract_flush_record_keys(zh, rec->sysno, 1, zh->reg->keys, 0);
1321 extract_flush_sort_keys(zh, rec->sysno, 1, zh->reg->sortKeys);
1323 xfree(rec->info[recInfo_delKeys]);
1324 zebra_rec_keys_get_buf(zh->reg->keys,
1325 &rec->info[recInfo_delKeys],
1326 &rec->size[recInfo_delKeys]);
1328 xfree(rec->info[recInfo_sortKeys]);
1329 zebra_rec_keys_get_buf(zh->reg->sortKeys,
1330 &rec->info[recInfo_sortKeys],
1331 &rec->size[recInfo_sortKeys]);
1335 void zebra_it_key_str_dump(ZebraHandle zh, struct it_key *key,
1336 const char *str, size_t slen, NMEM nmem, int level)
1338 char keystr[200]; /* room for zints to print */
1340 int ord = CAST_ZINT_TO_INT(key->mem[0]);
1341 const char *index_type;
1343 const char *string_index;
1345 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type,
1346 0/* db */, &string_index);
1348 zebra_term_untrans_iconv(zh, nmem, index_type,
1351 for (i = 0; i < key->len; i++)
1353 sprintf(keystr + strlen(keystr), ZINT_FORMAT " ", key->mem[i]);
1356 if (*str < CHR_BASE_CHAR)
1359 char dst_buf[200]; /* room for special chars */
1361 strcpy(dst_buf , "?");
1363 if (!strcmp(str, ""))
1364 strcpy(dst_buf, "alwaysmatches");
1365 if (!strcmp(str, FIRST_IN_FIELD_STR))
1366 strcpy(dst_buf, "firstinfield");
1367 else if (!strcmp(str, CHR_UNKNOWN))
1368 strcpy(dst_buf, "unknown");
1369 else if (!strcmp(str, CHR_SPACE))
1370 strcpy(dst_buf, "space");
1372 for (i = 0; i<slen; i++)
1374 sprintf(dst_buf + strlen(dst_buf), " %d", str[i] & 0xff);
1376 yaz_log(level, "%s%s %s %s", keystr, index_type,
1377 string_index, dst_buf);
1381 yaz_log(level, "%s%s %s \"%s\"", keystr, index_type,
1382 string_index, dst_term);
1385 void extract_rec_keys_log(ZebraHandle zh, int is_insert,
1386 zebra_rec_keys_t reckeys,
1389 if (zebra_rec_keys_rewind(reckeys))
1394 NMEM nmem = nmem_create();
1396 while(zebra_rec_keys_read(reckeys, &str, &slen, &key))
1398 zebra_it_key_str_dump(zh, &key, str, slen, nmem, level);
1405 void extract_rec_keys_adjust(ZebraHandle zh, int is_insert,
1406 zebra_rec_keys_t reckeys)
1408 ZebraExplainInfo zei = zh->reg->zei;
1412 struct ord_stat *next;
1415 if (zebra_rec_keys_rewind(reckeys))
1417 struct ord_stat *ord_list = 0;
1421 struct it_key key_in;
1422 while(zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1424 int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
1426 for (p = ord_list; p ; p = p->next)
1434 p = xmalloc(sizeof(*p));
1445 struct ord_stat *p1 = p;
1448 zebraExplain_ord_adjust_occurrences(zei, p->ord, p->no, 1);
1450 zebraExplain_ord_adjust_occurrences(zei, p->ord, - p->no, -1);
1458 static void extract_flush_record_keys2(
1459 ZebraHandle zh, zint sysno,
1460 zebra_rec_keys_t ins_keys, zint ins_rank,
1461 zebra_rec_keys_t del_keys, zint del_rank)
1463 ZebraExplainInfo zei = zh->reg->zei;
1467 if (!zh->reg->key_block)
1469 int mem = 1024*1024 * atoi( res_get_def( zh->res, "memmax", "8"));
1470 const char *key_tmp_dir = res_get_def(zh->res, "keyTmpDir", ".");
1471 int use_threads = atoi(res_get_def(zh->res, "threads", "1"));
1472 zh->reg->key_block = key_block_create(mem, key_tmp_dir, use_threads);
1477 extract_rec_keys_adjust(zh, 1, ins_keys);
1479 zebraExplain_recordCountIncrement(zei, 1);
1480 zebra_rec_keys_rewind(ins_keys);
1484 extract_rec_keys_adjust(zh, 0, del_keys);
1486 zebraExplain_recordCountIncrement(zei, -1);
1487 zebra_rec_keys_rewind(del_keys);
1493 const char *del_str;
1494 struct it_key del_key_in;
1498 const char *ins_str;
1499 struct it_key ins_key_in;
1503 del = zebra_rec_keys_read(del_keys, &del_str, &del_slen,
1506 ins = zebra_rec_keys_read(ins_keys, &ins_str, &ins_slen,
1509 if (del && ins && ins_rank == del_rank
1510 && !key_compare(&del_key_in, &ins_key_in)
1511 && ins_slen == del_slen && !memcmp(del_str, ins_str, del_slen))
1521 key_block_write(zh->reg->key_block, sysno,
1522 &del_key_in, 0, del_str, del_slen,
1523 del_rank, zh->m_staticrank);
1525 key_block_write(zh->reg->key_block, sysno,
1526 &ins_key_in, 1, ins_str, ins_slen,
1527 ins_rank, zh->m_staticrank);
1529 yaz_log(log_level_extract, "normal=%d optimized=%d", normal, optimized);
1532 static void extract_flush_record_keys(
1533 ZebraHandle zh, zint sysno, int cmd,
1534 zebra_rec_keys_t reckeys,
1537 ZebraExplainInfo zei = zh->reg->zei;
1539 extract_rec_keys_adjust(zh, cmd, reckeys);
1541 if (log_level_details)
1543 yaz_log(log_level_details, "Keys for record " ZINT_FORMAT " %s",
1544 sysno, cmd ? "insert" : "delete");
1545 extract_rec_keys_log(zh, cmd, reckeys, log_level_details);
1548 if (!zh->reg->key_block)
1550 int mem = 1024*1024 * atoi( res_get_def( zh->res, "memmax", "8"));
1551 const char *key_tmp_dir = res_get_def(zh->res, "keyTmpDir", ".");
1552 int use_threads = atoi(res_get_def(zh->res, "threads", "1"));
1553 zh->reg->key_block = key_block_create(mem, key_tmp_dir, use_threads);
1555 zebraExplain_recordCountIncrement(zei, cmd ? 1 : -1);
1558 yaz_log(YLOG_LOG, "sysno=" ZINT_FORMAT " cmd=%d", sysno, cmd);
1559 print_rec_keys(zh, reckeys);
1561 if (zebra_rec_keys_rewind(reckeys))
1565 struct it_key key_in;
1566 while(zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1568 key_block_write(zh->reg->key_block, sysno,
1569 &key_in, cmd, str, slen,
1570 staticrank, zh->m_staticrank);
1576 ZEBRA_RES zebra_rec_keys_to_snippets1(ZebraHandle zh,
1577 zebra_rec_keys_t reckeys,
1578 zebra_snippets *snippets)
1580 NMEM nmem = nmem_create();
1581 if (zebra_rec_keys_rewind(reckeys))
1586 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
1591 const char *index_type;
1593 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
1594 seqno = key.mem[key.len-1];
1595 ord = CAST_ZINT_TO_INT(key.mem[0]);
1597 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type,
1598 0/* db */, 0 /* string_index */);
1600 zebra_term_untrans_iconv(zh, nmem, index_type,
1602 zebra_snippets_append(snippets, seqno, 0, ord, dst_term);
1610 void print_rec_keys(ZebraHandle zh, zebra_rec_keys_t reckeys)
1612 yaz_log(YLOG_LOG, "print_rec_keys");
1613 if (zebra_rec_keys_rewind(reckeys))
1618 while (zebra_rec_keys_read(reckeys, &str, &slen, &key))
1620 char dst_buf[IT_MAX_WORD];
1622 const char *index_type;
1623 int ord = CAST_ZINT_TO_INT(key.mem[0]);
1625 assert(key.len <= IT_KEY_LEVEL_MAX && key.len > 2);
1627 zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db, 0);
1629 seqno = key.mem[key.len-1];
1631 zebra_term_untrans(zh, index_type, dst_buf, str);
1633 yaz_log(YLOG_LOG, "ord=%d seqno=" ZINT_FORMAT
1634 " term=%s", ord, seqno, dst_buf);
1639 static void extract_add_index_string(RecWord *p, zinfo_index_category_t cat,
1640 const char *str, int length)
1643 ZebraHandle zh = p->extractCtrl->handle;
1644 ZebraExplainInfo zei = zh->reg->zei;
1647 ch = zebraExplain_lookup_attr_str(zei, cat, p->index_type, p->index_name);
1649 ch = zebraExplain_add_attr_str(zei, cat, p->index_type, p->index_name);
1653 key.mem[i++] = p->record_id;
1654 key.mem[i++] = p->section_id;
1656 if (zh->m_segment_indexing)
1657 key.mem[i++] = p->segment;
1658 key.mem[i++] = p->seqno;
1661 zebra_rec_keys_write(zh->reg->keys, str, length, &key);
1664 static void extract_add_sort_string(RecWord *p, const char *str, int length)
1667 ZebraHandle zh = p->extractCtrl->handle;
1668 ZebraExplainInfo zei = zh->reg->zei;
1670 zinfo_index_category_t cat = zinfo_index_category_sort;
1672 ch = zebraExplain_lookup_attr_str(zei, cat, p->index_type, p->index_name);
1674 ch = zebraExplain_add_attr_str(zei, cat, p->index_type, p->index_name);
1677 key.mem[1] = p->record_id;
1678 key.mem[2] = p->section_id;
1680 zebra_rec_keys_write(zh->reg->sortKeys, str, length, &key);
1683 static void extract_add_staticrank_string(RecWord *p,
1684 const char *str, int length)
1687 struct recExtractCtrl *ctrl = p->extractCtrl;
1689 if (length > sizeof(valz)-1)
1690 length = sizeof(valz)-1;
1692 memcpy(valz, str, length);
1693 valz[length] = '\0';
1694 ctrl->staticrank = atozint(valz);
1697 static void extract_add_string(RecWord *p, zebra_map_t zm,
1698 const char *string, int length)
1704 if (log_level_details)
1707 WRBUF w = wrbuf_alloc();
1709 wrbuf_write_escaped(w, string, length);
1710 yaz_log(log_level_details, "extract_add_string: %s", wrbuf_cstr(w));
1713 if (zebra_maps_is_index(zm))
1715 extract_add_index_string(p, zinfo_index_category_index,
1717 if (zebra_maps_is_alwaysmatches(zm))
1720 memcpy(&word, p, sizeof(word));
1723 extract_add_index_string(
1724 &word, zinfo_index_category_alwaysmatches, "", 0);
1727 else if (zebra_maps_is_sort(zm))
1729 extract_add_sort_string(p, string, length);
1731 else if (zebra_maps_is_staticrank(zm))
1733 extract_add_staticrank_string(p, string, length);
1737 static void extract_add_incomplete_field(RecWord *p, zebra_map_t zm)
1739 const char *b = p->term_buf;
1740 int remain = p->term_len;
1742 const char **map = 0;
1745 map = zebra_maps_input(zm, &b, remain, 0);
1749 char buf[IT_MAX_WORD+1];
1753 while (map && *map && **map == *CHR_SPACE)
1755 remain = p->term_len - (b - p->term_buf);
1757 map = zebra_maps_input(zm, &b, remain, 0);
1764 while (map && *map && **map != *CHR_SPACE)
1766 const char *cp = *map;
1768 while (i < IT_MAX_WORD && *cp)
1770 remain = p->term_len - (b - p->term_buf);
1772 map = zebra_maps_input(zm, &b, remain, 0);
1782 if (zebra_maps_is_first_in_field(zm))
1784 /* first in field marker */
1785 extract_add_string(p, zm, FIRST_IN_FIELD_STR, FIRST_IN_FIELD_LEN);
1789 extract_add_string(p, zm, buf, i);
1794 static void extract_add_complete_field(RecWord *p, zebra_map_t zm)
1796 char buf[IT_MAX_WORD+1];
1797 int i = parse_complete_field(p, zm, buf);
1800 extract_add_string(p, zm, buf, i);
1804 static void extract_add_icu(RecWord *p, zebra_map_t zm)
1806 const char *res_buf = 0;
1809 zebra_map_tokenize_start(zm, p->term_buf, p->term_len);
1810 while (zebra_map_tokenize_next(zm, &res_buf, &res_len, 0, 0))
1812 if (res_len > IT_MAX_WORD)
1814 yaz_log(YLOG_LOG, "Truncating long term %ld", (long) res_len);
1815 res_len = IT_MAX_WORD;
1817 extract_add_string(p, zm, res_buf, res_len);
1823 /** \brief top-level indexing handler for recctrl system
1824 \param p token data to be indexed
1828 extract_add_{in}_complete / extract_add_icu
1831 extract_add_index_string
1833 extract_add_sort_string
1835 extract_add_staticrank_string
1838 static void extract_token_add(RecWord *p)
1840 ZebraHandle zh = p->extractCtrl->handle;
1841 zebra_map_t zm = zebra_map_get_or_add(zh->reg->zebra_maps, p->index_type);
1843 if (log_level_details)
1845 yaz_log(log_level_details, "extract_token_add "
1846 "type=%s index=%s seqno=" ZINT_FORMAT " s=%.*s",
1847 p->index_type, p->index_name,
1848 p->seqno, p->term_len, p->term_buf);
1850 if (zebra_maps_is_icu(zm))
1852 extract_add_icu(p, zm);
1856 if (zebra_maps_is_complete(zm))
1857 extract_add_complete_field(p, zm);
1859 extract_add_incomplete_field(p, zm);
1863 static void extract_set_store_data_cb(struct recExtractCtrl *p,
1864 void *buf, size_t sz)
1866 ZebraHandle zh = (ZebraHandle) p->handle;
1868 xfree(zh->store_data_buf);
1869 zh->store_data_buf = 0;
1870 zh->store_data_size = 0;
1873 zh->store_data_buf = xmalloc(sz);
1874 zh->store_data_size = sz;
1875 memcpy(zh->store_data_buf, buf, sz);
1879 static void extract_set_store_data_prepare(struct recExtractCtrl *p)
1881 ZebraHandle zh = (ZebraHandle) p->handle;
1882 xfree(zh->store_data_buf);
1883 zh->store_data_buf = 0;
1884 zh->store_data_size = 0;
1885 p->setStoreData = extract_set_store_data_cb;
1888 static void extract_schema_add(struct recExtractCtrl *p, Odr_oid *oid)
1890 ZebraHandle zh = (ZebraHandle) p->handle;
1891 zebraExplain_addSchema(zh->reg->zei, oid);
1894 void extract_flush_sort_keys(ZebraHandle zh, zint sysno,
1895 int cmd, zebra_rec_keys_t reckeys)
1898 yaz_log(YLOG_LOG, "extract_flush_sort_keys cmd=%d sysno=" ZINT_FORMAT,
1900 extract_rec_keys_log(zh, cmd, reckeys, YLOG_LOG);
1903 if (zebra_rec_keys_rewind(reckeys))
1905 zebra_sort_index_t si = zh->reg->sort_index;
1908 struct it_key key_in;
1910 NMEM nmem = nmem_create();
1911 struct sort_add_ent {
1914 struct sort_add_ent *next;
1919 struct sort_add_ent *sort_ent_list = 0;
1921 while (zebra_rec_keys_read(reckeys, &str, &slen, &key_in))
1923 int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
1924 zint filter_sysno = key_in.mem[1];
1925 zint section_id = key_in.mem[2];
1927 struct sort_add_ent **e = &sort_ent_list;
1928 for (; *e; e = &(*e)->next)
1929 if ((*e)->ord == ord && section_id == (*e)->section_id)
1933 *e = nmem_malloc(nmem, sizeof(**e));
1935 (*e)->wrbuf = wrbuf_alloc();
1938 (*e)->sysno = filter_sysno ? filter_sysno : sysno;
1939 (*e)->section_id = section_id;
1942 wrbuf_write((*e)->wrbuf, str, slen);
1943 wrbuf_putc((*e)->wrbuf, '\0');
1947 zint last_sysno = 0;
1948 struct sort_add_ent *e = sort_ent_list;
1949 for (; e; e = e->next)
1951 if (last_sysno != e->sysno)
1953 zebra_sort_sysno(si, e->sysno);
1954 last_sysno = e->sysno;
1956 zebra_sort_type(si, e->ord);
1958 zebra_sort_add(si, e->section_id, e->wrbuf);
1960 zebra_sort_delete(si, e->section_id);
1961 wrbuf_destroy(e->wrbuf);
1971 * c-file-style: "Stroustrup"
1972 * indent-tabs-mode: nil
1974 * vim: shiftwidth=4 tabstop=8 expandtab