+ *dst++ = 1;
+ }
+ if (dst == dstBuf)
+ {
+ logf (LOG_WARN, "No match criteria for record %s in group %s",
+ fname, zh->m_group ? zh->m_group : "none");
+ return NULL;
+ }
+ *dst = '\0';
+ return dstBuf;
+}
+
+struct recordLogInfo {
+ const char *fname;
+ int recordOffset;
+ struct recordGroup *rGroup;
+};
+
+void create_rec_keys_codec(struct recKeys *keys)
+{
+ keys->buf_used = 0;
+#if IT_KEY_NEW
+ iscz1_reset(keys->codec_handle);
+#else
+ keys->prevAttrUse = -1;
+ keys->prevAttrSet = -1;
+ keys->prevSeqNo = 0;
+#endif
+}
+
+static int file_extract_record(ZebraHandle zh,
+ SYSNO *sysno, const char *fname,
+ int deleteFlag,
+ struct file_read_info *fi,
+ int force_update)
+{
+ RecordAttr *recordAttr;
+ int r;
+ const char *matchStr;
+ SYSNO sysnotmp;
+ Record rec;
+ off_t recordOffset = 0;
+ RecType recType;
+ void *clientData;
+ char subType[128];
+
+ if (!(recType =
+ recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
+ &clientData)))
+ {
+ logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
+ return 0;
+ }
+
+ /* announce database */
+ if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
+ {
+ if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0],
+ zh->m_explain_database))
+ return 0;
+ }
+
+ if (fi->fd != -1)
+ {
+ struct recExtractCtrl extractCtrl;
+
+ /* we are going to read from a file, so prepare the extraction */
+ int i;
+
+ create_rec_keys_codec(&zh->reg->keys);
+
+ zh->reg->sortKeys.buf_used = 0;
+
+ recordOffset = fi->file_moffset;
+ extractCtrl.offset = fi->file_moffset;
+ extractCtrl.readf = file_read;
+ extractCtrl.seekf = file_seek;
+ extractCtrl.tellf = file_tell;
+ extractCtrl.endf = file_end;
+ extractCtrl.fh = fi;
+ extractCtrl.subType = subType;
+ extractCtrl.init = extract_init;
+ extractCtrl.tokenAdd = extract_token_add;
+ extractCtrl.schemaAdd = extract_schema_add;
+ extractCtrl.dh = zh->reg->dh;
+ extractCtrl.handle = zh;
+ for (i = 0; i<256; i++)
+ {
+ if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
+ extractCtrl.seqno[i] = 1;
+ else
+ extractCtrl.seqno[i] = 0;
+ }
+ extractCtrl.zebra_maps = zh->reg->zebra_maps;
+ extractCtrl.flagShowRecords = !zh->m_flag_rw;
+
+ if (!zh->m_flag_rw)
+ printf ("File: %s " PRINTF_OFF_T "\n", fname, recordOffset);
+ if (zh->m_flag_rw)
+ {
+ char msg[512];
+ sprintf (msg, "%s:" PRINTF_OFF_T , fname, recordOffset);
+ yaz_log_init_prefix2 (msg);
+ }
+
+ r = (*recType->extract)(clientData, &extractCtrl);
+
+ yaz_log_init_prefix2 (0);
+ if (r == RECCTRL_EXTRACT_EOF)
+ return 0;
+ else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
+ {
+ /* error occured during extraction ... */
+ if (zh->m_flag_rw &&
+ zh->records_processed < zh->m_file_verbose_limit)
+ {
+ logf (LOG_WARN, "fail %s %s " PRINTF_OFF_T, zh->m_record_type,
+ fname, recordOffset);
+ }
+ return 0;
+ }
+ else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
+ {
+ /* error occured during extraction ... */
+ if (zh->m_flag_rw &&
+ zh->records_processed < zh->m_file_verbose_limit)
+ {
+ logf (LOG_WARN, "no filter for %s %s "
+ PRINTF_OFF_T, zh->m_record_type,
+ fname, recordOffset);
+ }
+ return 0;
+ }
+ if (zh->reg->keys.buf_used == 0)
+ {
+ /* the extraction process returned no information - the record
+ is probably empty - unless flagShowRecords is in use */
+ if (!zh->m_flag_rw)
+ return 1;
+
+ logf (LOG_WARN, "empty %s %s " PRINTF_OFF_T, zh->m_record_type,
+ fname, recordOffset);
+ return 1;
+ }
+ }
+
+ /* perform match if sysno not known and if match criteria is specified */
+
+ matchStr = NULL;
+ if (!sysno)
+ {
+ sysnotmp = 0;
+ sysno = &sysnotmp;
+ if (zh->m_record_id && *zh->m_record_id)
+ {
+ char *rinfo;
+
+ matchStr = fileMatchStr (zh, &zh->reg->keys, fname,
+ zh->m_record_id);
+ if (matchStr)
+ {
+ rinfo = dict_lookup (zh->reg->matchDict, matchStr);
+ if (rinfo)
+ {
+ assert(*rinfo == sizeof(*sysno));
+ memcpy (sysno, rinfo+1, sizeof(*sysno));
+ }
+ }
+ else
+ {
+ logf (LOG_WARN, "Bad match criteria");
+ return 0;
+ }
+ }
+ }
+
+ if (! *sysno)
+ {
+ /* new record */
+ if (deleteFlag)
+ {
+ logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T, zh->m_record_type,
+ fname, recordOffset);
+ logf (LOG_WARN, "cannot delete record above (seems new)");
+ return 1;
+ }
+ if (zh->records_processed < zh->m_file_verbose_limit)
+ logf (LOG_LOG, "add %s %s " PRINTF_OFF_T, zh->m_record_type,
+ fname, recordOffset);
+ rec = rec_new (zh->reg->records);
+
+ *sysno = rec->sysno;
+
+ recordAttr = rec_init_attr (zh->reg->zei, rec);
+
+ if (matchStr)
+ {
+ dict_insert (zh->reg->matchDict, matchStr, sizeof(*sysno), sysno);
+ }
+ extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
+
+ zh->records_inserted++;
+ }
+ else
+ {
+ /* record already exists */
+ struct recKeys delkeys;
+ struct sortKeys sortKeys;
+
+ rec = rec_get (zh->reg->records, *sysno);
+ assert (rec);
+
+ recordAttr = rec_init_attr (zh->reg->zei, rec);
+
+ if (!force_update && recordAttr->runNumber ==
+ zebraExplain_runNumberIncrement (zh->reg->zei, 0))
+ {
+ yaz_log (LOG_LOG, "run number = %d", recordAttr->runNumber);
+ yaz_log (LOG_LOG, "skipped %s %s " PRINTF_OFF_T,
+ zh->m_record_type, fname, recordOffset);
+ extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
+ rec_rm (&rec);
+ logRecord (zh);
+ return 1;
+ }
+ delkeys.buf_used = rec->size[recInfo_delKeys];
+ delkeys.buf = rec->info[recInfo_delKeys];
+
+ sortKeys.buf_used = rec->size[recInfo_sortKeys];
+ sortKeys.buf = rec->info[recInfo_sortKeys];
+
+ extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
+ if (deleteFlag)
+ {
+ /* record going to be deleted */
+ if (!delkeys.buf_used)
+ {
+ logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
+ zh->m_record_type, fname, recordOffset);
+ logf (LOG_WARN, "cannot delete file above, storeKeys false");
+ }
+ else
+ {
+ if (zh->records_processed < zh->m_file_verbose_limit)
+ logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
+ zh->m_record_type, fname, recordOffset);
+ zh->records_deleted++;
+ if (matchStr)
+ dict_delete (zh->reg->matchDict, matchStr);
+ rec_del (zh->reg->records, &rec);
+ }
+ rec_rm (&rec);
+ logRecord (zh);
+ return 1;
+ }
+ else
+ {
+ /* record going to be updated */
+ if (!delkeys.buf_used)
+ {
+ logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
+ zh->m_record_type, fname, recordOffset);
+ logf (LOG_WARN, "cannot update file above, storeKeys false");
+ }
+ else
+ {
+ if (zh->records_processed < zh->m_file_verbose_limit)
+ logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
+ zh->m_record_type, fname, recordOffset);
+ extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
+ zh->records_updated++;
+ }
+ }
+ }
+ /* update file type */
+ xfree (rec->info[recInfo_fileType]);
+ rec->info[recInfo_fileType] =
+ rec_strdup (zh->m_record_type, &rec->size[recInfo_fileType]);
+
+ /* update filename */
+ xfree (rec->info[recInfo_filename]);
+ rec->info[recInfo_filename] =
+ rec_strdup (fname, &rec->size[recInfo_filename]);
+
+ /* update delete keys */
+ xfree (rec->info[recInfo_delKeys]);
+ if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
+ {
+ rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
+ rec->info[recInfo_delKeys] = zh->reg->keys.buf;
+ zh->reg->keys.buf = NULL;
+ zh->reg->keys.buf_max = 0;
+ }
+ else
+ {
+ rec->info[recInfo_delKeys] = NULL;
+ rec->size[recInfo_delKeys] = 0;
+ }
+
+ /* update sort keys */
+ xfree (rec->info[recInfo_sortKeys]);
+
+ rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
+ rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
+ zh->reg->sortKeys.buf = NULL;
+ zh->reg->sortKeys.buf_max = 0;
+
+ /* save file size of original record */
+ zebraExplain_recordBytesIncrement (zh->reg->zei,
+ - recordAttr->recordSize);
+ recordAttr->recordSize = fi->file_moffset - recordOffset;
+ if (!recordAttr->recordSize)
+ recordAttr->recordSize = fi->file_max - recordOffset;
+ zebraExplain_recordBytesIncrement (zh->reg->zei,
+ recordAttr->recordSize);
+
+ /* set run-number for this record */
+ recordAttr->runNumber = zebraExplain_runNumberIncrement (zh->reg->zei,
+ 0);
+
+ /* update store data */
+ xfree (rec->info[recInfo_storeData]);
+ if (zh->m_store_data)
+ {
+ rec->size[recInfo_storeData] = recordAttr->recordSize;
+ rec->info[recInfo_storeData] = (char *)
+ xmalloc (recordAttr->recordSize);
+ if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
+ {
+ logf (LOG_ERRNO|LOG_FATAL, "seek to " PRINTF_OFF_T " in %s",
+ recordOffset, fname);
+ exit (1);
+ }
+ if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
+ < recordAttr->recordSize)
+ {
+ logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
+ recordAttr->recordSize, fname);
+ exit (1);
+ }
+ }
+ else
+ {
+ rec->info[recInfo_storeData] = NULL;
+ rec->size[recInfo_storeData] = 0;
+ }
+ /* update database name */
+ xfree (rec->info[recInfo_databaseName]);
+ rec->info[recInfo_databaseName] =
+ rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]);
+
+ /* update offset */
+ recordAttr->recordOffset = recordOffset;
+
+ /* commit this record */
+ rec_put (zh->reg->records, &rec);
+ logRecord (zh);
+ return 1;
+}
+
+int fileExtract (ZebraHandle zh, SYSNO *sysno, const char *fname,
+ int deleteFlag)
+{
+ int r, i, fd;
+ char gprefix[128];
+ char ext[128];
+ char ext_res[128];
+ struct file_read_info *fi;
+ const char *original_record_type = 0;
+
+ if (!zh->m_group || !*zh->m_group)
+ *gprefix = '\0';
+ else
+ sprintf (gprefix, "%s.", zh->m_group);
+
+ logf (LOG_DEBUG, "fileExtract %s", fname);
+
+ /* determine file extension */
+ *ext = '\0';
+ for (i = strlen(fname); --i >= 0; )
+ if (fname[i] == '/')
+ break;
+ else if (fname[i] == '.')
+ {
+ strcpy (ext, fname+i+1);
+ break;
+ }
+ /* determine file type - depending on extension */
+ original_record_type = zh->m_record_type;
+ if (!zh->m_record_type)
+ {
+ sprintf (ext_res, "%srecordType.%s", gprefix, ext);
+ zh->m_record_type = res_get (zh->res, ext_res);
+ }
+ if (!zh->m_record_type)
+ {
+ if (zh->records_processed < zh->m_file_verbose_limit)
+ logf (LOG_LOG, "? %s", fname);
+ return 0;
+ }
+ /* determine match criteria */
+ if (!zh->m_record_id)
+ {
+ sprintf (ext_res, "%srecordId.%s", gprefix, ext);
+ zh->m_record_id = res_get (zh->res, ext_res);
+ }
+
+ if (sysno && deleteFlag)
+ fd = -1;
+ else
+ {
+ char full_rep[1024];
+
+ if (zh->path_reg && !yaz_is_abspath (fname))
+ {
+ strcpy (full_rep, zh->path_reg);
+ strcat (full_rep, "/");
+ strcat (full_rep, fname);
+ }
+ else
+ strcpy (full_rep, fname);
+
+
+ if ((fd = open (full_rep, O_BINARY|O_RDONLY)) == -1)
+ {
+ logf (LOG_WARN|LOG_ERRNO, "open %s", full_rep);
+ zh->m_record_type = original_record_type;
+ return 0;
+ }
+ }
+ fi = file_read_start (fd);
+ do
+ {
+ file_begin (fi);
+ r = file_extract_record (zh, sysno, fname, deleteFlag, fi, 1);
+ } while (r && !sysno && fi->file_more);
+ file_read_stop (fi);
+ if (fd != -1)
+ close (fd);
+ zh->m_record_type = original_record_type;
+ return r;
+}
+
+/*
+ If sysno is provided, then it's used to identify the reocord.
+ If not, and match_criteria is provided, then sysno is guessed
+ If not, and a record is provided, then sysno is got from there
+
+ */
+int buffer_extract_record (ZebraHandle zh,
+ const char *buf, size_t buf_size,
+ int delete_flag,
+ int test_mode,
+ const char *recordType,
+ SYSNO *sysno,
+ const char *match_criteria,
+ const char *fname,
+ int force_update,
+ int allow_update)
+{
+ RecordAttr *recordAttr;
+ struct recExtractCtrl extractCtrl;
+ int i, r;
+ const char *matchStr = 0;
+ RecType recType = NULL;
+ char subType[1024];
+ void *clientData;
+ Record rec;
+ long recordOffset = 0;
+ struct zebra_fetch_control fc;
+ const char *pr_fname = fname; /* filename to print .. */
+
+ if (!pr_fname)
+ pr_fname = "<no file>"; /* make it printable if file is omitted */
+
+ fc.fd = -1;
+ fc.record_int_buf = buf;
+ fc.record_int_len = buf_size;
+ fc.record_int_pos = 0;
+ fc.offset_end = 0;
+ fc.record_offset = 0;
+
+ extractCtrl.offset = 0;
+ extractCtrl.readf = zebra_record_int_read;
+ extractCtrl.seekf = zebra_record_int_seek;
+ extractCtrl.tellf = zebra_record_int_tell;
+ extractCtrl.endf = zebra_record_int_end;
+ extractCtrl.fh = &fc;
+
+ create_rec_keys_codec(&zh->reg->keys);
+
+ zh->reg->sortKeys.buf_used = 0;
+
+ if (zebraExplain_curDatabase (zh->reg->zei, zh->basenames[0]))
+ {
+ if (zebraExplain_newDatabase (zh->reg->zei, zh->basenames[0],
+ zh->m_explain_database))
+ return 0;
+ }
+
+ if (recordType && *recordType) {
+ logf (LOG_DEBUG, "Record type explicitly specified: %s", recordType);
+ recType = recType_byName (zh->reg->recTypes, recordType, subType,
+ &clientData);
+ } else {
+ if (!(zh->m_record_type)) {
+ logf (LOG_WARN, "No such record type defined");
+ return 0;
+ }
+ logf (LOG_DEBUG, "Get record type from rgroup: %s",zh->m_record_type);
+ recType = recType_byName (zh->reg->recTypes, zh->m_record_type, subType,
+ &clientData);
+ recordType = zh->m_record_type;
+ }
+
+ if (!recType) {
+ logf (LOG_WARN, "No such record type: %s", zh->m_record_type);
+ return 0;
+ }
+
+ extractCtrl.subType = subType;
+ extractCtrl.init = extract_init;
+ extractCtrl.tokenAdd = extract_token_add;
+ extractCtrl.schemaAdd = extract_schema_add;
+ extractCtrl.dh = zh->reg->dh;
+ extractCtrl.handle = zh;
+ extractCtrl.zebra_maps = zh->reg->zebra_maps;
+ extractCtrl.flagShowRecords = 0;
+ for (i = 0; i<256; i++)
+ {
+ if (zebra_maps_is_positioned(zh->reg->zebra_maps, i))
+ extractCtrl.seqno[i] = 1;
+ else
+ extractCtrl.seqno[i] = 0;
+ }
+
+ r = (*recType->extract)(clientData, &extractCtrl);
+
+ if (r == RECCTRL_EXTRACT_EOF)
+ return 0;
+ else if (r == RECCTRL_EXTRACT_ERROR_GENERIC)
+ {
+ /* error occured during extraction ... */
+ yaz_log (LOG_WARN, "extract error: generic");
+ return 0;
+ }
+ else if (r == RECCTRL_EXTRACT_ERROR_NO_SUCH_FILTER)
+ {
+ /* error occured during extraction ... */
+ yaz_log (LOG_WARN, "extract error: no such filter");
+ return 0;
+ }
+ if (zh->reg->keys.buf_used == 0)
+ {
+ /* the extraction process returned no information - the record
+ is probably empty - unless flagShowRecords is in use */
+ if (test_mode)
+ return 1;
+ logf (LOG_WARN, "No keys generated for record");
+ logf (LOG_WARN, " The file is probably empty");
+ return 1;
+ }
+ /* match criteria */
+ matchStr = NULL;
+
+ if (! *sysno) {
+ char *rinfo;
+ if (match_criteria && *match_criteria) {
+ matchStr = match_criteria;
+ } else {
+ if (zh->m_record_id && *zh->m_record_id) {
+ matchStr = fileMatchStr (zh, &zh->reg->keys, pr_fname,
+ zh->m_record_id);
+ if (!matchStr)
+ {
+ logf (LOG_WARN, "Bad match criteria (recordID)");
+ return 1;
+ }
+ }
+ }
+ if (matchStr) {
+ rinfo = dict_lookup (zh->reg->matchDict, matchStr);
+ if (rinfo)
+ {
+ assert(*rinfo == sizeof(*sysno));
+ memcpy (sysno, rinfo+1, sizeof(*sysno));
+ }
+ }
+ }
+
+ if (! *sysno)
+ {
+ /* new record */
+ if (delete_flag)
+ {
+ logf (LOG_LOG, "delete %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ logf (LOG_WARN, "cannot delete record above (seems new)");
+ return 1;
+ }
+ logf (LOG_LOG, "add %s %s %ld", recordType, pr_fname,
+ (long) recordOffset);
+ rec = rec_new (zh->reg->records);
+
+ *sysno = rec->sysno;
+
+ recordAttr = rec_init_attr (zh->reg->zei, rec);
+
+ if (matchStr)
+ {
+ dict_insert (zh->reg->matchDict, matchStr,
+ sizeof(*sysno), sysno);
+ }
+ extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
+
+ zh->records_inserted++;
+ }
+ else
+ {
+ /* record already exists */
+ struct recKeys delkeys;
+ struct sortKeys sortKeys;
+
+ if (!allow_update) {
+ logf (LOG_LOG, "skipped %s %s %ld",
+ recordType, pr_fname, (long) recordOffset);
+ logRecord(zh);
+ return -1;
+ }
+
+ rec = rec_get (zh->reg->records, *sysno);
+ assert (rec);
+
+ recordAttr = rec_init_attr (zh->reg->zei, rec);
+
+ if (!force_update) {
+ if (recordAttr->runNumber ==
+ zebraExplain_runNumberIncrement (zh->reg->zei, 0))
+ {
+ logf (LOG_LOG, "skipped %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ extract_flushSortKeys (zh, *sysno, -1, &zh->reg->sortKeys);
+ rec_rm (&rec);
+ logRecord(zh);
+ return -1;
+ }
+ }
+
+ delkeys.buf_used = rec->size[recInfo_delKeys];
+ delkeys.buf = rec->info[recInfo_delKeys];
+
+ sortKeys.buf_used = rec->size[recInfo_sortKeys];
+ sortKeys.buf = rec->info[recInfo_sortKeys];
+
+ extract_flushSortKeys (zh, *sysno, 0, &sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
+ if (delete_flag)
+ {
+ /* record going to be deleted */
+ if (!delkeys.buf_used)
+ {
+ logf (LOG_LOG, "delete %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ logf (LOG_WARN, "cannot delete file above, storeKeys false");
+ }
+ else
+ {
+ logf (LOG_LOG, "delete %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ zh->records_deleted++;
+ if (matchStr)
+ dict_delete (zh->reg->matchDict, matchStr);
+ rec_del (zh->reg->records, &rec);
+ }
+ rec_rm (&rec);
+ logRecord(zh);
+ return 0;
+ }
+ else
+ {
+ /* record going to be updated */
+ if (!delkeys.buf_used)
+ {
+ logf (LOG_LOG, "update %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ logf (LOG_WARN, "cannot update file above, storeKeys false");
+ }
+ else
+ {
+ logf (LOG_LOG, "update %s %s %ld", recordType,
+ pr_fname, (long) recordOffset);
+ extract_flushSortKeys (zh, *sysno, 1, &zh->reg->sortKeys);
+ extract_flushRecordKeys (zh, *sysno, 1, &zh->reg->keys);
+ zh->records_updated++;
+ }
+ }
+ }
+ /* update file type */
+ xfree (rec->info[recInfo_fileType]);
+ rec->info[recInfo_fileType] =
+ rec_strdup (recordType, &rec->size[recInfo_fileType]);
+
+ /* update filename */
+ xfree (rec->info[recInfo_filename]);
+ rec->info[recInfo_filename] =
+ rec_strdup (fname, &rec->size[recInfo_filename]);
+
+ /* update delete keys */
+ xfree (rec->info[recInfo_delKeys]);
+ if (zh->reg->keys.buf_used > 0 && zh->m_store_keys == 1)
+ {
+ rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
+ rec->info[recInfo_delKeys] = zh->reg->keys.buf;
+ zh->reg->keys.buf = NULL;
+ zh->reg->keys.buf_max = 0;
+ }
+ else
+ {
+ rec->info[recInfo_delKeys] = NULL;
+ rec->size[recInfo_delKeys] = 0;
+ }
+
+ /* update sort keys */
+ xfree (rec->info[recInfo_sortKeys]);
+
+ rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
+ rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
+ zh->reg->sortKeys.buf = NULL;
+ zh->reg->sortKeys.buf_max = 0;
+
+ /* save file size of original record */
+ zebraExplain_recordBytesIncrement (zh->reg->zei,
+ - recordAttr->recordSize);
+#if 0
+ recordAttr->recordSize = fi->file_moffset - recordOffset;
+ if (!recordAttr->recordSize)
+ recordAttr->recordSize = fi->file_max - recordOffset;
+#else
+ recordAttr->recordSize = buf_size;
+#endif
+ zebraExplain_recordBytesIncrement (zh->reg->zei,
+ recordAttr->recordSize);
+
+ /* set run-number for this record */
+ recordAttr->runNumber =
+ zebraExplain_runNumberIncrement (zh->reg->zei, 0);
+
+ /* update store data */
+ xfree (rec->info[recInfo_storeData]);
+ if (zh->m_store_data)
+ {
+ rec->size[recInfo_storeData] = recordAttr->recordSize;
+ rec->info[recInfo_storeData] = (char *)
+ xmalloc (recordAttr->recordSize);
+ memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
+ }
+ else
+ {
+ rec->info[recInfo_storeData] = NULL;
+ rec->size[recInfo_storeData] = 0;
+ }
+ /* update database name */
+ xfree (rec->info[recInfo_databaseName]);
+ rec->info[recInfo_databaseName] =
+ rec_strdup (zh->basenames[0], &rec->size[recInfo_databaseName]);
+
+ /* update offset */
+ recordAttr->recordOffset = recordOffset;
+
+ /* commit this record */
+ rec_put (zh->reg->records, &rec);
+ logRecord(zh);
+ return 0;
+}
+
+int explain_extract (void *handle, Record rec, data1_node *n)
+{
+ ZebraHandle zh = (ZebraHandle) handle;
+ struct recExtractCtrl extractCtrl;
+ int i;
+
+ if (zebraExplain_curDatabase (zh->reg->zei,
+ rec->info[recInfo_databaseName]))
+ {
+ abort();
+ if (zebraExplain_newDatabase (zh->reg->zei,
+ rec->info[recInfo_databaseName], 0))
+ abort ();
+ }
+
+ create_rec_keys_codec(&zh->reg->keys);
+
+ zh->reg->sortKeys.buf_used = 0;
+
+ extractCtrl.init = extract_init;
+ extractCtrl.tokenAdd = extract_token_add;
+ extractCtrl.schemaAdd = extract_schema_add;
+ extractCtrl.dh = zh->reg->dh;
+ for (i = 0; i<256; i++)
+ extractCtrl.seqno[i] = 0;
+ extractCtrl.zebra_maps = zh->reg->zebra_maps;
+ extractCtrl.flagShowRecords = 0;
+ extractCtrl.handle = handle;
+
+ if (n)
+ grs_extract_tree(&extractCtrl, n);
+
+ if (rec->size[recInfo_delKeys])
+ {
+ struct recKeys delkeys;
+ struct sortKeys sortkeys;
+
+ delkeys.buf_used = rec->size[recInfo_delKeys];
+ delkeys.buf = rec->info[recInfo_delKeys];
+
+ sortkeys.buf_used = rec->size[recInfo_sortKeys];
+ sortkeys.buf = rec->info[recInfo_sortKeys];
+
+ extract_flushSortKeys (zh, rec->sysno, 0, &sortkeys);
+ extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
+ }
+ extract_flushRecordKeys (zh, rec->sysno, 1, &zh->reg->keys);
+ extract_flushSortKeys (zh, rec->sysno, 1, &zh->reg->sortKeys);
+
+ xfree (rec->info[recInfo_delKeys]);
+ rec->size[recInfo_delKeys] = zh->reg->keys.buf_used;
+ rec->info[recInfo_delKeys] = zh->reg->keys.buf;
+ zh->reg->keys.buf = NULL;
+ zh->reg->keys.buf_max = 0;
+
+ xfree (rec->info[recInfo_sortKeys]);
+ rec->size[recInfo_sortKeys] = zh->reg->sortKeys.buf_used;
+ rec->info[recInfo_sortKeys] = zh->reg->sortKeys.buf;
+ zh->reg->sortKeys.buf = NULL;
+ zh->reg->sortKeys.buf_max = 0;
+
+ return 0;
+}
+
+void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
+ int cmd, struct recKeys *reckeys)
+{
+#if IT_KEY_NEW
+ void *decode_handle = iscz1_start();
+#else
+ int seqno = 0;
+#if SU_SCHEME
+#else
+ unsigned char attrSet = (unsigned char) -1;
+ unsigned short attrUse = (unsigned short) -1;
+#endif
+#endif
+ int off = 0;
+ int ch = 0;
+ ZebraExplainInfo zei = zh->reg->zei;
+
+ if (!zh->reg->key_buf)
+ {
+ int mem= 1024*1024* atoi( res_get_def( zh->res, "memmax", "8"));
+ if (mem <= 0)
+ {
+ logf(LOG_WARN, "Invalid memory setting, using default 8 MB");
+ mem= 1024*1024*8;
+ }
+ /* FIXME: That "8" should be in a default settings include */
+ /* not hard-coded here! -H */
+ zh->reg->key_buf = (char**) xmalloc (mem);
+ zh->reg->ptr_top = mem/sizeof(char*);
+ zh->reg->ptr_i = 0;
+ zh->reg->key_buf_used = 0;
+ zh->reg->key_file_no = 0;
+ }
+ zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
+#if IT_KEY_NEW
+ while (off < reckeys->buf_used)
+ {
+ const char *src = reckeys->buf + off;
+ struct it_key key;
+ char *dst = (char*) &key;
+ int attrSet, attrUse;
+
+ iscz1_decode(decode_handle, &dst, &src);
+ assert(key.len < 4 && key.len > 2);
+
+ attrSet = (int) key.mem[0];
+ attrUse = (int) key.mem[1]; /* sequence in mem[2] */
+
+ if (zh->reg->key_buf_used + 1024 >
+ (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
+ extract_flushWriteKeys (zh,0);
+ ++(zh->reg->ptr_i);
+ assert(zh->reg->ptr_i > 0);
+ (zh->reg->key_buf)[zh->reg->ptr_top - zh->reg->ptr_i] =
+ (char*)zh->reg->key_buf + zh->reg->key_buf_used;
+
+ ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
+ if (ch < 0)
+ ch = zebraExplain_addSU (zei, attrSet, attrUse);
+
+ assert (ch > 0);
+ zh->reg->key_buf_used +=
+ key_SU_encode (ch,((char*)zh->reg->key_buf) +
+ zh->reg->key_buf_used);
+ while (*src)
+ ((char*)zh->reg->key_buf) [(zh->reg->key_buf_used)++] = *src++;
+ src++;
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = '\0';
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = cmd;
+
+ key.len = 2;
+ key.mem[0] = sysno;
+ key.mem[1] = key.mem[2]; /* sequence .. */
+
+ memcpy ((char*)zh->reg->key_buf + zh->reg->key_buf_used,
+ &key, sizeof(key));
+ (zh->reg->key_buf_used) += sizeof(key);
+ off = src - reckeys->buf;
+ }
+#else
+ while (off < reckeys->buf_used)
+ {
+ const char *src = reckeys->buf + off;
+ struct it_key key;
+ int lead;
+
+ lead = *src++;
+
+#if SU_SCHEME
+ if ((lead & 3) < 3)
+ {
+ memcpy (&ch, src, sizeof(ch));
+ src += sizeof(ch);
+ }
+#else
+ if (!(lead & 1))
+ {
+ memcpy (&attrSet, src, sizeof(attrSet));
+ src += sizeof(attrSet);
+ }
+ if (!(lead & 2))
+ {
+ memcpy (&attrUse, src, sizeof(attrUse));
+ src += sizeof(attrUse);
+ }
+#endif
+ if (zh->reg->key_buf_used + 1024 >
+ (zh->reg->ptr_top -zh->reg->ptr_i)*sizeof(char*))
+ extract_flushWriteKeys (zh,0);
+ assert(zh->reg->ptr_i >= 0);
+ ++(zh->reg->ptr_i);
+ assert(zh->reg->ptr_i > 0);
+ (zh->reg->key_buf)[zh->reg->ptr_top - zh->reg->ptr_i] =
+ (char*)zh->reg->key_buf + zh->reg->key_buf_used;
+#if SU_SCHEME
+#else
+ ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
+ if (ch < 0)
+ ch = zebraExplain_addSU (zei, attrSet, attrUse);
+#endif
+ assert (ch > 0);
+ zh->reg->key_buf_used +=
+ key_SU_encode (ch,((char*)zh->reg->key_buf) +
+ zh->reg->key_buf_used);
+
+ while (*src)
+ ((char*)zh->reg->key_buf) [(zh->reg->key_buf_used)++] = *src++;
+ src++;
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = '\0';
+ ((char*)(zh->reg->key_buf))[(zh->reg->key_buf_used)++] = cmd;
+
+ if (lead & 60)
+ seqno += ((lead>>2) & 15)-1;
+ else
+ {
+ memcpy (&seqno, src, sizeof(seqno));
+ src += sizeof(seqno);
+ }
+ key.seqno = seqno;
+ key.sysno = sysno;
+ memcpy ((char*)zh->reg->key_buf + zh->reg->key_buf_used, &key, sizeof(key));
+ (zh->reg->key_buf_used) += sizeof(key);
+ off = src - reckeys->buf;
+ }
+#endif
+ assert (off == reckeys->buf_used);
+#if IT_KEY_NEW
+ iscz1_stop(decode_handle);
+#endif
+}
+
+void extract_flushWriteKeys (ZebraHandle zh, int final)
+ /* optimizing: if final=1, and no files written yet */
+ /* push the keys directly to merge, sidestepping the */
+ /* temp file altogether. Speeds small updates */
+{
+ FILE *outf;
+ char out_fname[200];
+ char *prevcp, *cp;
+ struct encode_info encode_info;
+ int ptr_i = zh->reg->ptr_i;
+ int temp_policy;
+#if SORT_EXTRA
+ int i;
+#endif
+ if (!zh->reg->key_buf || ptr_i <= 0)
+ {
+ logf (LOG_DEBUG, " nothing to flush section=%d buf=%p i=%d",
+ zh->reg->key_file_no, zh->reg->key_buf, ptr_i);
+ logf (LOG_DEBUG, " buf=%p ",
+ zh->reg->key_buf);
+ logf (LOG_DEBUG, " ptr=%d ",zh->reg->ptr_i);
+ logf (LOG_DEBUG, " reg=%p ",zh->reg);
+
+ return;
+ }
+
+ (zh->reg->key_file_no)++;
+ logf (LOG_LOG, "sorting section %d", (zh->reg->key_file_no));
+ logf (LOG_DEBUG, " sort_buff at %p n=%d",
+ zh->reg->key_buf + zh->reg->ptr_top - ptr_i,ptr_i);
+#if !SORT_EXTRA
+ qsort (zh->reg->key_buf + zh->reg->ptr_top - ptr_i, ptr_i,
+ sizeof(char*), key_qsort_compare);
+
+ /* zebra.cfg: tempfiles:
+ Y: always use temp files (old way)
+ A: use temp files, if more than one (auto)
+ = if this is both the last and the first
+ N: never bother with temp files (new) */
+
+ temp_policy=toupper(res_get_def(zh->res,"tempfiles","auto")[0]);
+ if (temp_policy != 'Y' && temp_policy != 'N' && temp_policy != 'A') {
+ logf (LOG_WARN, "Illegal tempfiles setting '%c'. using 'Auto' ",
+ temp_policy);
+ temp_policy='A';
+ }
+
+ if ( ( temp_policy =='N' ) || /* always from memory */
+ ( ( temp_policy =='A' ) && /* automatic */
+ (zh->reg->key_file_no == 1) && /* this is first time */
+ (final) ) ) /* and last (=only) time */
+ { /* go directly from memory */
+ zh->reg->key_file_no =0; /* signal not to read files */
+ zebra_index_merge(zh);
+ zh->reg->ptr_i = 0;
+ zh->reg->key_buf_used = 0;
+ return;
+ }
+
+ /* Not doing directly from memory, write into a temp file */
+ extract_get_fname_tmp (zh, out_fname, zh->reg->key_file_no);
+
+ if (!(outf = fopen (out_fname, "wb")))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
+ exit (1);
+ }
+ logf (LOG_LOG, "writing section %d", zh->reg->key_file_no);
+ prevcp = cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
+
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+
+ while (--ptr_i > 0)
+ {
+ cp = (zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
+ if (strcmp (cp, prevcp))
+ {
+ encode_key_flush ( &encode_info, outf);
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+ prevcp = cp;
+ }
+ else
+ encode_key_write (cp + strlen(cp), &encode_info, outf);
+ }
+ encode_key_flush ( &encode_info, outf);
+#else
+ qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
+ extract_get_fname_tmp (out_fname, key_file_no);
+
+ if (!(outf = fopen (out_fname, "wb")))
+ {
+ logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
+ exit (1);
+ }
+ logf (LOG_LOG, "writing section %d", key_file_no);
+ i = ptr_i;
+ prevcp = key_buf[ptr_top-i];
+ while (1)
+ if (!--i || strcmp (prevcp, key_buf[ptr_top-i]))
+ {
+ key_y_len = strlen(prevcp)+1;
+#if 0
+ logf (LOG_LOG, "key_y_len: %2d %02x %02x %s",
+ key_y_len, prevcp[0], prevcp[1], 2+prevcp);
+#endif
+ qsort (key_buf + ptr_top-ptr_i, ptr_i - i,
+ sizeof(char*), key_y_compare);
+ cp = key_buf[ptr_top-ptr_i];
+ --key_y_len;
+ encode_key_init (&encode_info);
+ encode_key_write (cp, &encode_info, outf);
+ while (--ptr_i > i)
+ {
+ cp = key_buf[ptr_top-ptr_i];
+ encode_key_write (cp+key_y_len, &encode_info, outf);
+ }
+ encode_key_flush ( &encode_info, outf);
+ if (!i)
+ break;
+ prevcp = key_buf[ptr_top-ptr_i];
+ }
+#endif
+ if (fclose (outf))