Work on new API. Locking system re-implemented
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 20 Feb 2002 17:30:01 +0000 (17:30 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 20 Feb 2002 17:30:01 +0000 (17:30 +0000)
32 files changed:
CHANGELOG
LICENSE.zebra
README
configure.in
include/zebraver.h
index/Makefile.am
index/extract.c
index/index.h
index/invstat.c
index/kinput.c
index/lockidx.c
index/lockutil.c
index/main.c
index/trav.c
index/zebraapi.c
index/zebraapi.h
index/zinfo.c
index/zinfo.h
index/zserver.c
index/zserver.h
index/zsets.c
recctrl/recgrs.c
rset/rstemp.c
test/Makefile.am
test/api/Makefile.am [new file with mode: 0644]
test/api/t1.c [new file with mode: 0644]
test/api/t1.cfg [new file with mode: 0644]
test/api/t2.c [new file with mode: 0644]
test/api/t2.cfg [new file with mode: 0644]
test/gils/Makefile.am
zebra.spec
zmbol.spec

index 29990f0..6fa36f5 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,10 @@
 
+--- 1.2 2002/MM/DD
+
+New Zebra API. Locking system re-implemented. Beware!
+
+--- 1.1.stable 2002/02/20
+
 Rank weight can be controlled with attribute type 9. Default
 value is 34. Recommended values between 1-36.
 
index b986a65..e66fe41 100644 (file)
@@ -1,5 +1,5 @@
 Zebra
-Copyright (c) 1995-1999 Index Data ApS.
+Copyright (c) 1995-2002 Index Data ApS.
 
 All rights reserved.
 
diff --git a/README b/README
index 9fe345e..bba6caa 100644 (file)
--- a/README
+++ b/README
@@ -1,8 +1,8 @@
-Copyright (C) 1995-2001, Index Data ApS.
+Copyright (C) 1995-2002, Index Data ApS.
 See the file LICENSE.zebra for details.
 
 README for Zebra
-  $Id: README,v 1.5 2001-02-21 11:23:17 adam Exp $
+  $Id: README,v 1.6 2002-02-20 17:30:01 adam Exp $
 
 Documentation about this software can be found in the subdirectory
 'doc' and Zebra's home page:  http://www.indexdata.dk/zebra/
index 6f82b86..0f7e458 100644 (file)
@@ -1,5 +1,5 @@
-dnl Zebra, Index Data Aps, 1994-2000
-dnl $Id: configure.in,v 1.29 2001-10-15 19:53:43 adam Exp $
+dnl Zebra, Index Data Aps, 1994-2002
+dnl $Id: configure.in,v 1.30 2002-02-20 17:30:01 adam Exp $
 dnl
 AC_INIT(include/zebraver.h)
 AC_MSG_CHECKING(for package)
@@ -152,5 +152,5 @@ AC_OUTPUT([
   include/Makefile
   tab/Makefile
   doc/Makefile
-  test/Makefile test/gils/Makefile test/usmarc/Makefile
+  test/Makefile test/gils/Makefile test/usmarc/Makefile test/api/Makefile
 ])
index 3baa595..7b906f5 100644 (file)
@@ -1,14 +1,14 @@
 /*
- * Copyright (C) 1994-2001, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  *
- * $Id: zebraver.h,v 1.18 2001-10-15 19:53:43 adam Exp $
+ * $Id: zebraver.h,v 1.19 2002-02-20 17:30:01 adam Exp $
  */
 
 #ifndef ZEBRAVER
-#define ZEBRAVER "1.1"
+#define ZEBRAVER "1.1.1"
 #endif
 
 #ifndef ZEBRADATE
-#define ZEBRADATE "$Date: 2001-10-15 19:53:43 $"
+#define ZEBRADATE "$Date: 2002-02-20 17:30:01 $"
 #endif
index db03d64..2f5d6ad 100644 (file)
@@ -1,49 +1,44 @@
-## $Id: Makefile.am,v 1.6 2001-10-15 20:57:18 adam Exp $
+## $Id: Makefile.am,v 1.7 2002-02-20 17:30:01 adam Exp $
 
 noinst_PROGRAMS = apitest kdump
 
+noinst_LIBRARIES = libzebra.a
+
+libzebra_a_SOURCES = dir.c dirs.c trav.c kinput.c kcompare.c \
+ attribute.c symtab.c recindex.c recstat.c lockutil.c  \
+ zebraapi.c zinfo.c invstat.c sortidx.c compact.c zsets.c zrpn.c \
+ rank1.c trunc.c retrieve.c extract.c
+
+if ISZMBOL
+zmbol_libs = ../isam/libisam.a ../isamc/libisamc.a ../isamb/libisamb.a
+else
+zmbol_libs =
+endif
+
+libzebra_a_LIBADD = \
+ ../rset/librset.a ../dict/libdict.a  ../isams/libisams.a \
+ $(zmbol_libs) ../recctrl/librecctrl.a ../bfile/libbfile.a ../dfa/libdfa.a \
+ ../util/libutil.a
+
 if ISZMBOL
 bin_PROGRAMS = zmbolidx zmbolsrv 
-zmbolidx_SOURCES = main.c dir.c dirs.c trav.c extract.c kinput.c kcompare.c \
- symtab.c recindex.c recstat.c lockutil.c lockidx.c \
- zinfo.c invstat.c sortidx.c compact.c \
- index.h recindex.h recindxp.h zebraapi.h zinfo.h zserver.h
-
-zmbolsrv_SOURCES = zserver.c kcompare.c zrpn.c zsets.c attribute.c recindex.c \
- lockutil.c locksrv.c zinfo.c trunc.c sortidx.c rank1.c zebraapi.c \
- retrieve.c kinput.c \
- index.h recindex.h recindxp.h zebraapi.h zinfo.h zserver.h
 else
 bin_PROGRAMS = zebraidx zebrasrv
-zebraidx_SOURCES = main.c dir.c dirs.c trav.c extract.c kinput.c kcompare.c \
- symtab.c recindex.c recstat.c lockutil.c lockidx.c \
- zinfo.c invstat.c sortidx.c compact.c \
- index.h recindex.h recindxp.h zebraapi.h zinfo.h zserver.h
-
-zebrasrv_SOURCES = zserver.c kcompare.c zrpn.c zsets.c attribute.c recindex.c \
- lockutil.c locksrv.c zinfo.c trunc.c sortidx.c rank1.c zebraapi.c \
- retrieve.c kinput.c \
- index.h recindex.h recindxp.h zebraapi.h zinfo.h zserver.h
 endif
 
-apitest_SOURCES = apitest.c kcompare.c zrpn.c zsets.c attribute.c recindex.c \
- lockutil.c locksrv.c zinfo.c trunc.c sortidx.c rank1.c zebraapi.c \
- retrieve.c kinput.c \
- index.h recindex.h recindxp.h zebraapi.h zinfo.h zserver.h
-
+zmbolidx_SOURCES = main.c
+zmbolsrv_SOURCES = zserver.c
+zebraidx_SOURCES = main.c
+zebrasrv_SOURCES = zserver.c
+apitest_SOURCES = apitest.c
 kdump_SOURCES=kdump.c kcompare.c
 
 CFLAGS = -I$(srcdir)/../include $(YAZINC) $(TCL_INCLUDE)
 
-if ISZMBOL
-zmbol_libs = ../isam/libisam.a ../isamc/libisamc.a ../isamb/libisamb.a
-else
-zmbol_libs =
-endif
+LDADD = libzebra.a $(YAZLIB) $(TCL_LIB)
 
-LDADD = \
- ../rset/librset.a ../dict/libdict.a  ../isams/libisams.a \
- $(zmbol_libs) \
- ../recctrl/librecctrl.a ../bfile/libbfile.a ../dfa/libdfa.a \
- ../util/libutil.a \
- $(YAZLIB) $(TCL_LIB)
+libzebra.a: $(libzebra_a_OBJECTS) $(libzebra_a_DEPENDENCIES)
+       -test ! -d atmp && mkdir atmp
+       mkdir atmp; for i in $(libzebra_a_LIBADD); do cd atmp; ar x ../$$i; cd ..; done
+       ar qc libzebra.a $(libzebra_a_OBJECTS) libzebra.a atmp/*.o
+       $(RANLIB) libzebra.a
index 86de3b2..a726916 100644 (file)
@@ -1,392 +1,9 @@
 /*
- * Copyright (C) 1994-2001, Index Data 
+ * Copyright (C) 1994-2002, Index Data 
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Log: extract.c,v $
- * Revision 1.109  2001-10-15 19:53:43  adam
- * POSIX thread updates. First work on term sets.
- *
- * Revision 1.108  2001/06/14 11:44:56  adam
- * Bug fix: default storeKeys setting wasn't read when group was specified.
- *
- * Revision 1.107  2001/05/28 13:58:48  adam
- * Call flushSortKeys when record is skipped to fix bad re-use of
- * sort keys to whatever next record that comes in.
- *
- * Revision 1.106  2000/12/05 12:22:53  adam
- * Termlist source implemented (so that we can index values of XML/SGML
- * attributes).
- *
- * Revision 1.105  2000/12/05 10:01:44  adam
- * Fixed bug regarding user-defined attribute sets.
- *
- * Revision 1.104  2000/09/05 14:04:05  adam
- * Updates for prefix 'yaz_' for YAZ log functions.
- *
- * Revision 1.103  2000/05/18 12:01:36  adam
- * System call times(2) used again. More 64-bit fixes.
- *
- * Revision 1.102  2000/05/15 15:32:33  adam
- * Added 64 bit file input.
- *
- * Revision 1.101  2000/05/15 13:02:39  adam
- * Minor change.
- *
- * Revision 1.100  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.99  2000/02/24 10:57:02  adam
- * Sequence number incremented after each incomplete-field.
- *
- * Revision 1.98  1999/09/07 07:19:21  adam
- * Work on character mapping. Implemented replace rules.
- *
- * Revision 1.97  1999/07/06 12:28:04  adam
- * Updated record index structure. Format includes version ID. Compression
- * algorithm ID is stored for each record block.
- *
- * Revision 1.96  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.95  1999/05/21 12:00:17  adam
- * Better diagnostics for extraction process.
- *
- * Revision 1.94  1999/05/20 12:57:18  adam
- * Implemented TCL filter. Updated recctrl system.
- *
- * Revision 1.93  1999/05/15 14:36:38  adam
- * Updated dictionary. Implemented "compression" of dictionary.
- *
- * Revision 1.92  1999/03/09 16:27:49  adam
- * More work on SDRKit integration.
- *
- * Revision 1.91  1999/02/12 13:29:22  adam
- * Implemented position-flag for registers.
- *
- * Revision 1.90  1999/02/02 14:50:52  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.89  1998/10/28 10:54:38  adam
- * SDRKit integration.
- *
- * Revision 1.88  1998/10/16 08:14:29  adam
- * Updated record control system.
- *
- * Revision 1.87  1998/10/15 13:10:33  adam
- * Fixed bug in Zebra that caused it to stop indexing when empty
- * record was read.
- *
- * Revision 1.86  1998/10/13 20:33:53  adam
- * Fixed one log message and change use ordinal to be an unsigned char.
- *
- * Revision 1.85  1998/09/22 10:03:41  adam
- * Changed result sets to be persistent in the sense that they can
- * be re-searched if needed.
- * Fixed memory leak in rsm_or.
- *
- * Revision 1.84  1998/06/11 15:42:22  adam
- * Changed the way use attributes are specified in the recordId
- * specification.
- *
- * Revision 1.83  1998/06/08 14:43:10  adam
- * Added suport for EXPLAIN Proxy servers - added settings databasePath
- * and explainDatabase to facilitate this. Increased maximum number
- * of databases and attributes in one register.
- *
- * Revision 1.82  1998/05/20 10:12:15  adam
- * Implemented automatic EXPLAIN database maintenance.
- * Modified Zebra to work with ASN.1 compiled version of YAZ.
- *
- * Revision 1.81  1998/03/11 11:19:04  adam
- * Changed the way sequence numbers are generated.
- *
- * Revision 1.80  1998/03/05 08:45:11  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.79  1998/02/17 10:32:52  adam
- * Fixed bug: binary files weren't opened with flag b on NT.
- *
- * Revision 1.78  1998/02/10 12:03:05  adam
- * Implemented Sort.
- *
- * Revision 1.77  1998/01/12 15:04:08  adam
- * The test option (-s) only uses read-lock (and not write lock).
- *
- * Revision 1.76  1997/10/27 14:33:04  adam
- * Moved towards generic character mapping depending on "structure"
- * field in abstract syntax file. Fixed a few memory leaks. Fixed
- * bug with negative integers when doing searches with relational
- * operators.
- *
- * Revision 1.75  1997/09/17 12:19:12  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.74  1997/09/09 13:38:06  adam
- * Partial port to WIN95/NT.
- *
- * Revision 1.73  1997/09/04 13:57:20  adam
- * New file extract/retrieve method tellf (added).
- * Added O_BINARY for open calls.
- *
- * Revision 1.72  1997/07/15 16:32:29  adam
- * Bug fix: Match handler didn't terminate the resulting string!
- *
- * Revision 1.71  1997/07/15 16:28:41  adam
- * Bug fix: storeData didn't work with files with multiple records.
- * Bug fix: fixed memory management with records; not really well
- *  thought through.
- *
- * Revision 1.70  1997/07/01 13:00:42  adam
- * Bug fix in routine searchRecordKey: uninitialized variables.
- *
- * Revision 1.69  1997/04/29 09:26:03  adam
- * Bug fix: generic recordId handling didn't work for compressed internal
- * keys.
- *
- * Revision 1.68  1997/02/12 20:39:45  adam
- * Implemented options -f <n> that limits the log to the first <n>
- * records.
- * Changed some log messages also.
- *
- * Revision 1.67  1996/11/15 15:02:14  adam
- * Minor changes regarding logging.
- *
- * Revision 1.66  1996/11/14  09:52:21  adam
- * Strings in record keys bound by IT_MAX_WORD.
- *
- * Revision 1.65  1996/11/14  08:57:56  adam
- * Reduction of storeKeys area.
- *
- * Revision 1.64  1996/11/08 11:10:16  adam
- * Buffers used during file match got bigger.
- * Compressed ISAM support everywhere.
- * Bug fixes regarding masking characters in queries.
- * Redesigned Regexp-2 queries.
- *
- * Revision 1.63  1996/10/29 14:09:39  adam
- * Use of cisam system - enabled if setting isamc is 1.
- *
- * Revision 1.62  1996/10/11 10:57:01  adam
- * New module recctrl. Used to manage records (extract/retrieval).
- * Several files have been moved to the recctrl sub directory.
- *
- * Revision 1.61  1996/06/06 12:08:37  quinn
- * Added showRecord function
- *
- * Revision 1.60  1996/06/04  10:18:12  adam
- * Search/scan uses character mapping module.
- *
- * Revision 1.59  1996/05/14  15:47:07  adam
- * Cleanup of various buffer size entities.
- *
- * Revision 1.58  1996/05/14  06:16:38  adam
- * Compact use/set bytes used in search service.
- *
- * Revision 1.57  1996/05/13 14:23:04  adam
- * Work on compaction of set/use bytes in dictionary.
- *
- * Revision 1.56  1996/05/09  09:54:42  adam
- * Server supports maps from one logical attributes to a list of physical
- * attributes.
- * The extraction process doesn't make space consuming 'any' keys.
- *
- * Revision 1.55  1996/05/09  07:28:55  quinn
- * Work towards phrases and multiple registers
- *
- * Revision 1.54  1996/05/01  13:46:35  adam
- * First work on multiple records in one file.
- * New option, -offset, to the "unread" command in the filter module.
- *
- * Revision 1.53  1996/04/26  12:09:43  adam
- * Added a few comments.
- *
- * Revision 1.52  1996/04/25  13:27:57  adam
- * Function recordExtract modified so that files with no keys (possibly empty)
- * are ignored.
- *
- * Revision 1.51  1996/03/19  11:08:42  adam
- * Bug fix: Log preamble wasn't always turned off after recordExtract.
- *
- * Revision 1.50  1996/02/12  18:45:36  adam
- * New fileVerboseFlag in record group control.
- *
- * Revision 1.49  1996/02/05  12:29:57  adam
- * Logging reduced a bit.
- * The remaining running time is estimated during register merge.
- *
- * Revision 1.48  1996/02/01  20:53:26  adam
- * The temporary per-record keys are compacted a little, and duplication
- * of the per-records keys are avoided when they are saved in the record
- * information buffer.
- *
- * Revision 1.47  1996/01/17  14:57:48  adam
- * Prototype changed for reader functions in extract/retrieve. File
- *  is identified by 'void *' instead of 'int.
- *
- * Revision 1.46  1995/12/15  14:57:16  adam
- * Bug fix.
- *
- * Revision 1.45  1995/12/15  12:37:41  adam
- * In addRecordKeyAny: Writes key only when attrSet != -1.
- *
- * Revision 1.44  1995/12/12  16:00:54  adam
- * System call sync(2) used after update/commit.
- * Locking (based on fcntl) uses F_EXLCK and F_SHLCK instead of F_WRLCK
- * and F_RDLCK.
- *
- * Revision 1.43  1995/12/11  09:12:46  adam
- * The rec_get function returns NULL if record doesn't exist - will
- * happen in the server if the result set records have been deleted since
- * the creation of the set (i.e. the search).
- * The server saves a result temporarily if it is 'volatile', i.e. the
- * set is register dependent.
- *
- * Revision 1.42  1995/12/07  17:38:46  adam
- * Work locking mechanisms for concurrent updates/commit.
- *
- * Revision 1.41  1995/12/06  16:06:42  adam
- * Better diagnostics. Work on 'real' dictionary deletion.
- *
- * Revision 1.40  1995/12/05  16:57:40  adam
- * More work on regular patterns.
- *
- * Revision 1.39  1995/12/05  13:20:18  adam
- * Bug fix: file_read sometimes returned early EOF.
- *
- * Revision 1.38  1995/12/04  17:59:21  adam
- * More work on regular expression conversion.
- *
- * Revision 1.37  1995/12/04  14:22:27  adam
- * Extra arg to recType_byName.
- * Started work on new regular expression parsed input to
- * structured records.
- *
- * Revision 1.36  1995/11/30  08:34:29  adam
- * Started work on commit facility.
- * Changed a few malloc/free to xmalloc/xfree.
- *
- * Revision 1.35  1995/11/28  14:26:21  adam
- * Bug fix: recordId with constant wasn't right.
- * Bug fix: recordId dictionary entry wasn't deleted when needed.
- *
- * Revision 1.34  1995/11/28  09:09:38  adam
- * Zebra config renamed.
- * Use setting 'recordId' to identify record now.
- * Bug fix in recindex.c: rec_release_blocks was invokeded even
- * though the blocks were already released.
- * File traversal properly deletes records when needed.
- *
- * Revision 1.33  1995/11/27  09:56:20  adam
- * Record info elements better enumerated. Internal store of records.
- *
- * Revision 1.32  1995/11/25  10:24:05  adam
- * More record fields - they are enumerated now.
- * New options: flagStoreData flagStoreKey.
- *
- * Revision 1.31  1995/11/24  11:31:35  adam
- * Commands add & del read filenames from stdin if source directory is
- * empty.
- * Match criteria supports 'constant' strings.
- *
- * Revision 1.30  1995/11/22  17:19:16  adam
- * Record management uses the bfile system.
- *
- * Revision 1.29  1995/11/21  15:01:14  adam
- * New general match criteria implemented.
- * New feature: document groups.
- *
- * Revision 1.28  1995/11/21  09:20:30  adam
- * Yet more work on record match.
- *
- * Revision 1.27  1995/11/20  16:59:45  adam
- * New update method: the 'old' keys are saved for each records.
- *
- * Revision 1.26  1995/11/20  11:56:24  adam
- * Work on new traversal.
- *
- * Revision 1.25  1995/11/16  15:34:54  adam
- * Uses new record management system in both indexer and server.
- *
- * Revision 1.24  1995/11/15  19:13:08  adam
- * Work on record management.
- *
- * Revision 1.23  1995/10/27  14:00:10  adam
- * Implemented detection of database availability.
- *
- * Revision 1.22  1995/10/17  18:02:07  adam
- * New feature: databases. Implemented as prefix to words in dictionary.
- *
- * Revision 1.21  1995/10/10  12:24:38  adam
- * Temporary sort files are compressed.
- *
- * Revision 1.20  1995/10/06  13:52:05  adam
- * Bug fixes. Handler may abort further scanning.
- *
- * Revision 1.19  1995/10/04  12:55:16  adam
- * Bug fix in ranked search. Use=Any keys inserted.
- *
- * Revision 1.18  1995/10/04  09:37:08  quinn
- * Fixed bug.
- *
- * Revision 1.17  1995/10/03  14:28:57  adam
- * Buffered read in extract works.
- *
- * Revision 1.16  1995/10/03  14:28:45  adam
- * Work on more effecient read handler in extract.
- *
- * Revision 1.15  1995/10/02  15:42:53  adam
- * Extract uses file descriptors instead of FILE pointers.
- *
- * Revision 1.14  1995/10/02  15:29:13  adam
- * More logging in file_extract.
- *
- * Revision 1.13  1995/09/29  14:01:39  adam
- * Bug fixes.
- *
- * Revision 1.12  1995/09/28  14:22:56  adam
- * Sort uses smaller temporary files.
- *
- * Revision 1.11  1995/09/28  12:10:31  adam
- * Bug fixes. Field prefix used in queries.
- *
- * Revision 1.10  1995/09/28  09:19:41  adam
- * xfree/xmalloc used everywhere.
- * Extract/retrieve method seems to work for text records.
- *
- * Revision 1.9  1995/09/27  12:22:28  adam
- * More work on extract in record control.
- * Field name is not in isam keys but in prefix in dictionary words.
- *
- * Revision 1.8  1995/09/14  07:48:22  adam
- * Record control management.
- *
- * Revision 1.7  1995/09/11  13:09:32  adam
- * More work on relevance feedback.
- *
- * Revision 1.6  1995/09/08  14:52:27  adam
- * Minor changes. Dictionary is lower case now.
- *
- * Revision 1.5  1995/09/06  16:11:16  adam
- * Option: only one word key per file.
- *
- * Revision 1.4  1995/09/05  15:28:39  adam
- * More work on search engine.
- *
- * Revision 1.3  1995/09/04  12:33:41  adam
- * Various cleanup. YAZ util used instead.
- *
- * Revision 1.2  1995/09/04  09:10:34  adam
- * More work on index add/del/update.
- * Merge sort implemented.
- * Initial work on z39 server.
- *
- * Revision 1.1  1995/09/01  14:06:35  adam
- * Split of work into more files.
- *
+ * $Id: extract.c,v 1.110 2002-02-20 17:30:01 adam Exp $
  */
 #include <stdio.h>
 #include <assert.h>
 #include <charmap.h>
 #include <sortidx.h>
 #include "index.h"
-
+#include "zserver.h"
 #include "zinfo.h"
 
 #if _FILE_OFFSET_BITS == 64
 #include "zebrasdr.h"
 #endif
 
-static Dict matchDict;
-
-static Records records = NULL;
-static SortIdx sortIdx = NULL;
-
-static char **key_buf;
-static size_t ptr_top;
-static size_t ptr_i;
-static size_t key_buf_used;
-static int key_file_no;
-
 static int records_inserted = 0;
 static int records_updated = 0;
 static int records_deleted = 0;
 static int records_processed = 0;
 
-static ZebraExplainInfo zti = NULL;
-
-
 static void logRecord (int showFlag)
 {
     if (!showFlag)
@@ -449,1412 +52,1609 @@ static void logRecord (int showFlag)
     }
 }
 
-static int explain_extract (void *handle, Record drec, data1_node *n);
+static void extract_init (struct recExtractCtrl *p, RecWord *w)
+{
+    w->zebra_maps = p->zebra_maps;
+    w->seqnos = p->seqno;
+    w->attrSet = VAL_BIB1;
+    w->attrUse = 1016;
+    w->reg_type = 'w';
+    w->extractCtrl = p;
+}
 
-int key_open (struct recordGroup *rGroup, int mem)
+static const char **searchRecordKey (ZebraHandle zh,
+                                     struct recKeys *reckeys,
+                                    int attrSetS, int attrUseS)
 {
-    BFiles bfs = rGroup->bfs;
-    int rw = rGroup->flagRw;
-    data1_handle dh = rGroup->dh;
-    char *recordCompression;
-    int record_compression = REC_COMPRESS_NONE;
-    if (!mem)
-        mem = atoi(res_get_def (common_resource, "memMax", "16"))*1024*1024;
-    if (mem < 50000)
-        mem = 50000;
-    key_buf = (char **) xmalloc (mem);
-    ptr_top = mem/sizeof(char*);
-    ptr_i = 0;
-
-    key_buf_used = 0;
-    key_file_no = 0;
-
-    if (!(matchDict = dict_open (bfs, GMATCH_DICT, 50, rw, 0)))
-    {
-        logf (LOG_FATAL, "dict_open fail of %s", GMATCH_DICT);
-       return -1;
-    }
-    assert (!records);
-    recordCompression = res_get_def (common_resource,
-                                    "recordCompression", "none");
-    if (!strcmp (recordCompression, "none"))
-       record_compression = REC_COMPRESS_NONE;
-    if (!strcmp (recordCompression, "bzip2"))
-       record_compression = REC_COMPRESS_BZIP2;
-    records = rec_open (bfs, rw, record_compression);
-    if (!records)
-    {
-       dict_close (matchDict);
-       return -1;
-    }
-    zti = zebraExplain_open (records, dh, common_resource,
-                            rw, rGroup, explain_extract);
-    if (!zti)
+    static const char *ws[32];
+    int off = 0;
+    int startSeq = -1;
+    int i;
+    int seqno = 0;
+#if SU_SCHEME
+    int chS, ch;
+#else
+    short attrUse;
+    char attrSet;
+#endif
+
+    for (i = 0; i<32; i++)
+        ws[i] = NULL;
+
+#if SU_SCHEME
+    chS = zebraExplain_lookupSU (zh->service->zei, attrSetS, attrUseS);
+    if (chS < 0)
+       return ws;
+#endif
+    while (off < reckeys->buf_used)
     {
-       rec_close (&records);
-       dict_close (matchDict);
-       return -1;      
+
+        const char *src = reckeys->buf + off;
+       const char *wstart;
+        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
+        wstart = src;
+        while (*src++)
+            ;
+        if (lead & 60)
+            seqno += ((lead>>2) & 15)-1;
+        else
+        {
+            memcpy (&seqno, src, sizeof(seqno));
+            src += sizeof(seqno);
+        }
+       if (
+#if SU_SCHEME
+           ch == chS
+#else
+           attrUseS == attrUse && attrSetS == attrSet
+#endif
+           )
+        {
+            int woff;
+
+
+            if (startSeq == -1)
+                startSeq = seqno;
+            woff = seqno - startSeq;
+            if (woff >= 0 && woff < 31)
+                ws[woff] = wstart;
+        }
+
+        off = src - reckeys->buf;
     }
-    sortIdx = sortIdx_open (bfs, 1);
-    return 0;
+    assert (off == reckeys->buf_used);
+    return ws;
 }
 
-struct encode_info {
-    int  sysno;
-    int  seqno;
-    int  cmd;
-    char buf[768];
+struct file_read_info {
+    off_t file_max;        /* maximum offset so far */
+    off_t file_offset;      /* current offset */
+    off_t file_moffset;     /* offset of rec/rec boundary */
+    int file_more;
+    int fd;
+    char *sdrbuf;
+    int sdrmax;
 };
 
-void encode_key_init (struct encode_info *i)
+static struct file_read_info *file_read_start (int fd)
 {
-    i->sysno = 0;
-    i->seqno = 0;
-    i->cmd = -1;
+    struct file_read_info *fi = (struct file_read_info *)
+       xmalloc (sizeof(*fi));
+
+    fi->fd = fd;
+    fi->file_max = 0;
+    fi->file_moffset = 0;
+    fi->sdrbuf = 0;
+    fi->sdrmax = 0;
+    return fi;
 }
 
-char *encode_key_int (int d, char *bp)
+static void file_read_stop (struct file_read_info *fi)
 {
-    if (d <= 63)
-        *bp++ = d;
-    else if (d <= 16383)
-    {
-        *bp++ = 64 + (d>>8);
-        *bp++ = d  & 255;
-    }
-    else if (d <= 4194303)
-    {
-        *bp++ = 128 + (d>>16);
-        *bp++ = (d>>8) & 255;
-        *bp++ = d & 255;
-    }
-    else
-    {
-        *bp++ = 192 + (d>>24);
-        *bp++ = (d>>16) & 255;
-        *bp++ = (d>>8) & 255;
-        *bp++ = d & 255;
-    }
-    return bp;
+    xfree (fi);
 }
 
-void encode_key_write (char *k, struct encode_info *i, FILE *outf)
+static off_t file_seek (void *handle, off_t offset)
 {
-    struct it_key key;
-    char *bp = i->buf;
-
-    while ((*bp++ = *k++))
-        ;
-    memcpy (&key, k+1, sizeof(struct it_key));
-    bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
-    if (i->sysno != key.sysno)
+    struct file_read_info *p = (struct file_read_info *) handle;
+    p->file_offset = offset;
+    if (p->sdrbuf)
+       return offset;
+    return lseek (p->fd, offset, SEEK_SET);
+}
+
+static off_t file_tell (void *handle)
+{
+    struct file_read_info *p = (struct file_read_info *) handle;
+    return p->file_offset;
+}
+
+static int file_read (void *handle, char *buf, size_t count)
+{
+    struct file_read_info *p = (struct file_read_info *) handle;
+    int fd = p->fd;
+    int r;
+    if (p->sdrbuf)
     {
-        i->sysno = key.sysno;
-        i->seqno = 0;
+       r = count;
+       if (r > p->sdrmax - p->file_offset)
+           r = p->sdrmax - p->file_offset;
+       if (r)
+           memcpy (buf, p->sdrbuf + p->file_offset, r);
     }
-    else if (!i->seqno && !key.seqno && i->cmd == *k)
-       return;
-    bp = encode_key_int (key.seqno - i->seqno, bp);
-    i->seqno = key.seqno;
-    i->cmd = *k;
-    if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
+    else
+       r = read (fd, buf, count);
+    if (r > 0)
     {
-        logf (LOG_FATAL|LOG_ERRNO, "fwrite");
-        exit (1);
+        p->file_offset += r;
+        if (p->file_offset > p->file_max)
+            p->file_max = p->file_offset;
     }
+    return r;
 }
 
-#define SORT_EXTRA 0
-
-#if SORT_EXTRA
-static int key_y_len;
-
-static int key_y_compare (const void *p1, const void *p2)
+static void file_begin (void *handle)
 {
-    int r;
+    struct file_read_info *p = (struct file_read_info *) handle;
 
-    if ((r = key_compare (*(char**) p1 + key_y_len + 1,
-                          *(char**) p2 + key_y_len + 1)))
-         return r;
-    return *(*(char**) p1 + key_y_len) - *(*(char**) p2 + key_y_len);
+    p->file_offset = p->file_moffset;
+    if (!p->sdrbuf && p->file_moffset)
+        lseek (p->fd, p->file_moffset, SEEK_SET);
+    p->file_more = 0;
 }
 
-static int key_x_compare (const void *p1, const void *p2)
+static void file_end (void *handle, off_t offset)
 {
-    return strcmp (*(char**) p1, *(char**) p2);
+    struct file_read_info *p = (struct file_read_info *) handle;
+
+    assert (p->file_more == 0);
+    p->file_more = 1;
+    p->file_moffset = offset;
 }
-#endif
 
-void key_flush (void)
+static char *fileMatchStr (ZebraHandle zh, 
+                           struct recKeys *reckeys, struct recordGroup *rGroup,
+                           const char *fname, const char *spec)
 {
-    FILE *outf;
-    char out_fname[200];
-    char *prevcp, *cp;
-    struct encode_info encode_info;
-#if SORT_EXTRA
-    int i;
-#endif
-    
-    if (ptr_i <= 0)
-        return;
-
-    key_file_no++;
-    logf (LOG_LOG, "sorting section %d", key_file_no);
-#if !SORT_EXTRA
-    qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_qsort_compare);
-    getFnameTmp (common_resource, out_fname, key_file_no);
+    static char dstBuf[2048];      /* static here ??? */
+    char *dst = dstBuf;
+    const char *s = spec;
+    static const char **w;
 
-    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);
-    prevcp = cp = key_buf[ptr_top-ptr_i];
-    
-    encode_key_init (&encode_info);
-    encode_key_write (cp, &encode_info, outf);
-    while (--ptr_i > 0)
+    while (1)
     {
-        cp = key_buf[ptr_top-ptr_i];
-        if (strcmp (cp, prevcp))
+        while (*s == ' ' || *s == '\t')
+            s++;
+        if (!*s)
+            break;
+        if (*s == '(')
         {
-            encode_key_init (&encode_info);
-            encode_key_write (cp, &encode_info, outf);
-            prevcp = cp;
+           char attset_str[64], attname_str[64];
+           data1_attset *attset;
+           int i;
+            char matchFlag[32];
+            int attSet = 1, attUse = 1;
+            int first = 1;
+
+            s++;
+           for (i = 0; *s && *s != ',' && *s != ')'; s++)
+               if (i < 63)
+                   attset_str[i++] = *s;
+           attset_str[i] = '\0';
+
+           if (*s == ',')
+           {
+               s++;
+               for (i = 0; *s && *s != ')'; s++)
+                   if (i < 63)
+                       attname_str[i++] = *s;
+               attname_str[i] = '\0';
+           }
+           
+           if ((attset = data1_get_attset (zh->service->dh, attset_str)))
+           {
+               data1_att *att;
+               attSet = attset->reference;
+               att = data1_getattbyname(zh->service->dh, attset, attname_str);
+               if (att)
+                   attUse = att->value;
+               else
+                   attUse = atoi (attname_str);
+           }
+            w = searchRecordKey (zh, reckeys, attSet, attUse);
+            assert (w);
+
+            if (*s == ')')
+            {
+                for (i = 0; i<32; i++)
+                    matchFlag[i] = 1;
+            }
+            else
+            {
+                logf (LOG_WARN, "Missing ) in match criteria %s in group %s",
+                      spec, rGroup->groupName ? rGroup->groupName : "none");
+                return NULL;
+            }
+            s++;
+
+            for (i = 0; i<32; i++)
+                if (matchFlag[i] && w[i])
+                {
+                    if (first)
+                    {
+                        *dst++ = ' ';
+                        first = 0;
+                    }
+                    strcpy (dst, w[i]);
+                    dst += strlen(w[i]);
+                }
+            if (first)
+            {
+                logf (LOG_WARN, "Record didn't contain match"
+                      " fields in (%s,%s)", attset_str, attname_str);
+                return NULL;
+            }
         }
-        else
-            encode_key_write (cp + strlen(cp), &encode_info, outf);
-    }
-#else
-    qsort (key_buf + ptr_top-ptr_i, ptr_i, sizeof(char*), key_x_compare);
-    getFnameTmp (out_fname, key_file_no);
+        else if (*s == '$')
+        {
+            int spec_len;
+            char special[64];
+            const char *spec_src = NULL;
+            const char *s1 = ++s;
+            while (*s1 && *s1 != ' ' && *s1 != '\t')
+                s1++;
 
-    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]))
+            spec_len = s1 - s;
+            if (spec_len > 63)
+                spec_len = 63;
+            memcpy (special, s, spec_len);
+            special[spec_len] = '\0';
+            s = s1;
+
+            if (!strcmp (special, "group"))
+                spec_src = rGroup->groupName;
+            else if (!strcmp (special, "database"))
+                spec_src = rGroup->databaseName;
+            else if (!strcmp (special, "filename"))
+                spec_src = fname;
+            else if (!strcmp (special, "type"))
+                spec_src = rGroup->recordType;
+            else 
+                spec_src = NULL;
+            if (spec_src)
+            {
+                strcpy (dst, spec_src);
+                dst += strlen (spec_src);
+            }
+        }
+        else if (*s == '\"' || *s == '\'')
         {
-            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)
+            int stopMarker = *s++;
+            char tmpString[64];
+            int i = 0;
+
+            while (*s && *s != stopMarker)
             {
-                cp = key_buf[ptr_top-ptr_i];
-                encode_key_write (cp+key_y_len, &encode_info, outf);
+                if (i < 63)
+                    tmpString[i++] = *s++;
             }
-            if (!i)
-                break;
-            prevcp = key_buf[ptr_top-ptr_i];
+            if (*s)
+                s++;
+            tmpString[i] = '\0';
+            strcpy (dst, tmpString);
+            dst += strlen (tmpString);
         }
-#endif
-    if (fclose (outf))
+        else
+        {
+            logf (LOG_WARN, "Syntax error in match criteria %s in group %s",
+                  spec, rGroup->groupName ? rGroup->groupName : "none");
+            return NULL;
+        }
+        *dst++ = 1;
+    }
+    if (dst == dstBuf)
     {
-        logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
-        exit (1);
+        logf (LOG_WARN, "No match criteria for record %s in group %s",
+              fname, rGroup->groupName ? rGroup->groupName : "none");
+        return NULL;
     }
-    logf (LOG_LOG, "finished section %d", key_file_no);
-    ptr_i = 0;
-    key_buf_used = 0;
-}
-
-int key_close (struct recordGroup *rGroup)
-{
-    int rw = rGroup->flagRw;
-    if (rw)
-       zebraExplain_runNumberIncrement (zti, 1);
-    zebraExplain_close (zti, rw);
-    key_flush ();
-    xfree (key_buf);
-    rec_close (&records);
-    dict_close (matchDict);
-    sortIdx_close (sortIdx);
-
-    logRecord (1);
-    return key_file_no;
+    *dst = '\0';
+    return dstBuf;
 }
 
-static void wordInit (struct recExtractCtrl *p, RecWord *w)
-{
-    w->zebra_maps = p->zebra_maps;
-    w->seqnos = p->seqno;
-    w->attrSet = VAL_BIB1;
-    w->attrUse = 1016;
-    w->reg_type = 'w';
-    w->extractCtrl = p;
-}
-
-static struct sortKey {
-    char *string;
-    int length;
-    int attrSet;
-    int attrUse;
-    struct sortKey *next;
-} *sortKeys = NULL;
-
-static struct recKeys {
-    int buf_used;
-    int buf_max;
-    char *buf;
-    char prevAttrSet;
-    short prevAttrUse;
-    int prevSeqNo;
-} reckeys;
-
-static void addIndexString (RecWord *p, const char *string, int length)
-{
-    char *dst;
-    unsigned char attrSet;
-    unsigned short attrUse;
-    int lead = 0;
-    int diff = 0;
-    int *pseqno = &p->seqnos[p->reg_type];
-
-    if (reckeys.buf_used+1024 > reckeys.buf_max)
-    {
-        char *b;
-
-        b = (char *) xmalloc (reckeys.buf_max += 128000);
-        if (reckeys.buf_used > 0)
-            memcpy (b, reckeys.buf, reckeys.buf_used);
-        xfree (reckeys.buf);
-        reckeys.buf = b;
-    }
-    dst = reckeys.buf + reckeys.buf_used;
-
-    attrSet = p->attrSet;
-    if (reckeys.buf_used > 0 && reckeys.prevAttrSet == attrSet)
-        lead |= 1;
-    else
-        reckeys.prevAttrSet = attrSet;
-    attrUse = p->attrUse;
-    if (reckeys.buf_used > 0 && reckeys.prevAttrUse == attrUse)
-        lead |= 2;
-    else
-        reckeys.prevAttrUse = attrUse;
-#if 1
-    diff = 1 + *pseqno - reckeys.prevSeqNo;
-    if (diff >= 1 && diff <= 15)
-        lead |= (diff << 2);
-    else
-        diff = 0;
-#endif
-    reckeys.prevSeqNo = *pseqno;
-    
-    *dst++ = lead;
-
-#if SU_SCHEME
-    if ((lead & 3) < 3)
-    {
-        int ch = zebraExplain_lookupSU (zti, attrSet, attrUse);
-        if (ch < 0)
-        {
-            ch = zebraExplain_addSU (zti, attrSet, attrUse);
-        }
-       assert (ch > 0);
-       memcpy (dst, &ch, sizeof(ch));
-       dst += sizeof(ch);
-    }
-#else
-    if (!(lead & 1))
-    {
-        memcpy (dst, &attrSet, sizeof(attrSet));
-        dst += sizeof(attrSet);
-    }
-    if (!(lead & 2))
-    {
-        memcpy (dst, &attrUse, sizeof(attrUse));
-        dst += sizeof(attrUse);
-    }
-#endif
-    *dst++ = p->reg_type;
-    memcpy (dst, string, length);
-    dst += length;
-    *dst++ = '\0';
-
-    if (!diff)
-    {
-        memcpy (dst, pseqno, sizeof(*pseqno));
-        dst += sizeof(*pseqno);
-    }
-    reckeys.buf_used = dst - reckeys.buf;
-    if (*pseqno)
-       (*pseqno)++;
-}
-
-static void addSortString (RecWord *p, const char *string, int length)
+struct recordLogInfo {
+    const char *fname;
+    int recordOffset;
+    struct recordGroup *rGroup;
+};
+     
+static void recordLogPreamble (int level, const char *msg, void *info)
 {
-    struct sortKey *sk;
-
-    for (sk = sortKeys; sk; sk = sk->next)
-       if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
-           return;
-
-    sk = (struct sortKey *) xmalloc (sizeof(*sk));
-    sk->next = sortKeys;
-    sortKeys = sk;
-
-    sk->string = (char *) xmalloc (length);
-    sk->length = length;
-    memcpy (sk->string, string, length);
+    struct recordLogInfo *p = (struct recordLogInfo *) info;
+    FILE *outf = yaz_log_file ();
 
-    sk->attrSet = p->attrSet;
-    sk->attrUse = p->attrUse;
+    if (level & LOG_LOG)
+        return ;
+    fprintf (outf, "File %s, offset %d, type %s\n",
+             p->rGroup->recordType, p->recordOffset, p->fname);
+    log_event_start (NULL, NULL);
 }
 
-static void addString (RecWord *p, const char *string, int length)
-{
-    assert (length > 0);
-    if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
-       addSortString (p, string, length);
-    else
-       addIndexString (p, string, length);
-}
 
-static void addIncompleteField (RecWord *p)
+static int recordExtract (ZebraHandle zh,
+                          SYSNO *sysno, const char *fname,
+                          struct recordGroup *rGroup, int deleteFlag,
+                          struct file_read_info *fi,
+                         RecType recType, char *subType, void *clientData)
 {
-    const char *b = p->string;
-    int remain = p->length;
-    const char **map = 0;
-
-    if (remain > 0)
-       map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+    RecordAttr *recordAttr;
+    int r;
+    char *matchStr;
+    SYSNO sysnotmp;
+    Record rec;
+    struct recordLogInfo logInfo;
+    off_t recordOffset = 0;
 
-    while (map)
+    if (fi->fd != -1)
     {
-       char buf[IT_MAX_WORD+1];
-       int i, remain;
+       struct recExtractCtrl extractCtrl;
 
-       /* Skip spaces */
-       while (map && *map && **map == *CHR_SPACE)
+        /* we are going to read from a file, so prepare the extraction */
+       int i;
+
+       zh->keys.buf_used = 0;
+       zh->keys.prevAttrUse = -1;
+       zh->keys.prevAttrSet = -1;
+       zh->keys.prevSeqNo = 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->service->dh;
+        extractCtrl.handle = zh;
+       for (i = 0; i<256; i++)
        {
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+           if (zebra_maps_is_positioned(zh->service->zebra_maps, i))
+               extractCtrl.seqno[i] = 1;
            else
-               map = 0;
+               extractCtrl.seqno[i] = 0;
        }
-       if (!map)
-           break;
-       i = 0;
-       while (map && *map && **map != *CHR_SPACE)
-       {
-           const char *cp = *map;
+       extractCtrl.zebra_maps = zh->service->zebra_maps;
+       extractCtrl.flagShowRecords = !rGroup->flagRw;
 
-           while (i < IT_MAX_WORD && *cp)
-               buf[i++] = *(cp++);
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
-           else
-               map = 0;
-       }
-       if (!i)
-           return;
-       addString (p, buf, i);
-    }
-    (p->seqnos[p->reg_type])++; /* to separate this from next one  */
-}
+        if (!rGroup->flagRw)
+            printf ("File: %s " PRINTF_OFF_T "\n", fname, recordOffset);
 
-static void addCompleteField (RecWord *p)
-{
-    const char *b = p->string;
-    char buf[IT_MAX_WORD+1];
-    const char **map = 0;
-    int i = 0, remain = p->length;
+        logInfo.fname = fname;
+        logInfo.recordOffset = recordOffset;
+        logInfo.rGroup = rGroup;
+        log_event_start (recordLogPreamble, &logInfo);
 
-    if (remain > 0)
-       map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
+        r = (*recType->extract)(clientData, &extractCtrl);
 
-    while (remain > 0 && i < IT_MAX_WORD)
-    {
-       while (map && *map && **map == *CHR_SPACE)
-       {
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
-           else
-               map = 0;
-       }
-       if (!map)
-           break;
+        log_event_start (NULL, NULL);
 
-       if (i && i < IT_MAX_WORD)
-           buf[i++] = *CHR_SPACE;
-       while (map && *map && **map != *CHR_SPACE)
+       if (r == RECCTRL_EXTRACT_EOF)
+           return 0;
+       else if (r == RECCTRL_EXTRACT_ERROR)
        {
-           const char *cp = *map;
-
-           if (i >= IT_MAX_WORD)
-               break;
-           while (i < IT_MAX_WORD && *cp)
-               buf[i++] = *(cp++);
-           remain = p->length  - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
-                                       remain);
-           else
-               map = 0;
-       }
+            /* error occured during extraction ... */
+            if (rGroup->flagRw &&
+               records_processed < rGroup->fileVerboseLimit)
+            {
+                logf (LOG_WARN, "fail %s %s " PRINTF_OFF_T, rGroup->recordType,
+                      fname, recordOffset);
+            }
+            return 0;
+        }
+        if (zh->keys.buf_used == 0)
+        {
+            /* the extraction process returned no information - the record
+               is probably empty - unless flagShowRecords is in use */
+            if (!rGroup->flagRw)
+                return 1;
+           
+           logf (LOG_WARN, "empty %s %s " PRINTF_OFF_T, rGroup->recordType,
+                 fname, recordOffset);
+            return 1;
+        }
     }
-    if (!i)
-       return;
-    addString (p, buf, i);
-}
 
-static void addRecordKey (RecWord *p)
-{
-    WRBUF wrbuf;
-    if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
-                              p->string, p->length)))
+    /* perform match if sysno not known and if match criteria is specified */
+       
+    matchStr = NULL;
+    if (!sysno) 
     {
-       p->string = wrbuf_buf(wrbuf);
-       p->length = wrbuf_len(wrbuf);
+        sysnotmp = 0;
+        sysno = &sysnotmp;
+        if (rGroup->recordId && *rGroup->recordId)
+        {
+            char *rinfo;
+        
+            matchStr = fileMatchStr (zh, &zh->keys, rGroup, fname, 
+                                     rGroup->recordId);
+            if (matchStr)
+            {
+                rinfo = dict_lookup (zh->service->matchDict, matchStr);
+                if (rinfo)
+                    memcpy (sysno, rinfo+1, sizeof(*sysno));
+            }
+            else
+            {
+                logf (LOG_WARN, "Bad match criteria");
+                return 0;
+            }
+        }
     }
-    if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
-       addCompleteField (p);
-    else
-       addIncompleteField(p);
-}
 
-static void flushSortKeys (SYSNO sysno, int cmd)
-{
-    struct sortKey *sk = sortKeys;
-
-    sortIdx_sysno (sortIdx, sysno);
-    while (sk)
+    if (! *sysno)
     {
-       struct sortKey *sk_next = sk->next;
-       if (cmd >= 0)
-       {
-           sortIdx_type (sortIdx, sk->attrUse);
-           sortIdx_add (sortIdx, sk->string, sk->length);
-       }
-       xfree (sk->string);
-       xfree (sk);
-       sk = sk_next;
-    }
-    sortKeys = NULL;
-}
+        /* new record */
+        if (deleteFlag)
+        {
+           logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T, rGroup->recordType,
+                 fname, recordOffset);
+            logf (LOG_WARN, "cannot delete record above (seems new)");
+            return 1;
+        }
+        if (records_processed < rGroup->fileVerboseLimit)
+            logf (LOG_LOG, "add %s %s " PRINTF_OFF_T, rGroup->recordType,
+                  fname, recordOffset);
+        rec = rec_new (zh->service->records);
 
-static void flushRecordKeys (SYSNO sysno, int cmd, struct recKeys *reckeys)
-{
-#if SU_SCHEME
-#else
-    unsigned char attrSet = (unsigned char) -1;
-    unsigned short attrUse = (unsigned short) -1;
-#endif
-    int seqno = 0;
-    int off = 0;
-    int ch = 0;
+        *sysno = rec->sysno;
 
-    zebraExplain_recordCountIncrement (zti, cmd ? 1 : -1);
-    while (off < reckeys->buf_used)
+       recordAttr = rec_init_attr (zh->service->zei, rec);
+
+        if (matchStr)
+        {
+            dict_insert (zh->service->matchDict, matchStr, sizeof(*sysno), sysno);
+        }
+        extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
+       extract_flushSortKeys (zh, *sysno, 1, &zh->sortKeys);
+
+        records_inserted++;
+    }
+    else
     {
-        const char *src = reckeys->buf + off;
-        struct it_key key;
-        int lead;
-    
-        lead = *src++;
+        /* record already exists */
+        struct recKeys delkeys;
 
-#if SU_SCHEME
-       if ((lead & 3) < 3)
+        rec = rec_get (zh->service->records, *sysno);
+        assert (rec);
+       
+       recordAttr = rec_init_attr (zh->service->zei, rec);
+
+       if (recordAttr->runNumber ==
+            zebraExplain_runNumberIncrement (zh->service->zei, 0))
        {
-           memcpy (&ch, src, sizeof(ch));
-           src += sizeof(ch);
+           logf (LOG_LOG, "skipped %s %s " PRINTF_OFF_T, rGroup->recordType,
+                 fname, recordOffset);
+           extract_flushSortKeys (zh, *sysno, -1, &zh->sortKeys);
+           rec_rm (&rec);
+           logRecord (0);
+           return 1;
        }
-#else
-        if (!(lead & 1))
+        delkeys.buf_used = rec->size[recInfo_delKeys];
+       delkeys.buf = rec->info[recInfo_delKeys];
+       extract_flushSortKeys (zh, *sysno, 0, &zh->sortKeys);
+        extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
+        if (deleteFlag)
         {
-            memcpy (&attrSet, src, sizeof(attrSet));
-            src += sizeof(attrSet);
+            /* record going to be deleted */
+            if (!delkeys.buf_used)
+            {
+                logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
+                      rGroup->recordType, fname, recordOffset);
+                logf (LOG_WARN, "cannot delete file above, storeKeys false");
+            }
+            else
+            {
+                if (records_processed < rGroup->fileVerboseLimit)
+                    logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
+                         rGroup->recordType, fname, recordOffset);
+                records_deleted++;
+                if (matchStr)
+                    dict_delete (zh->service->matchDict, matchStr);
+                rec_del (zh->service->records, &rec);
+            }
+           rec_rm (&rec);
+            logRecord (0);
+            return 1;
         }
-        if (!(lead & 2))
+        else
         {
-            memcpy (&attrUse, src, sizeof(attrUse));
-            src += sizeof(attrUse);
+            /* record going to be updated */
+            if (!delkeys.buf_used)
+            {
+                logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
+                      rGroup->recordType, fname, recordOffset);
+                logf (LOG_WARN, "cannot update file above, storeKeys false");
+            }
+            else
+            {
+                if (records_processed < rGroup->fileVerboseLimit)
+                    logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
+                        rGroup->recordType, fname, recordOffset);
+                extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
+                records_updated++;
+            }
         }
-#endif
-        if (key_buf_used + 1024 > (ptr_top-ptr_i)*sizeof(char*))
-            key_flush ();
-        ++ptr_i;
+    }
+    /* update file type */
+    xfree (rec->info[recInfo_fileType]);
+    rec->info[recInfo_fileType] =
+        rec_strdup (rGroup->recordType, &rec->size[recInfo_fileType]);
 
-        key_buf[ptr_top-ptr_i] = (char*)key_buf + key_buf_used;
+    /* update filename */
+    xfree (rec->info[recInfo_filename]);
+    rec->info[recInfo_filename] =
+        rec_strdup (fname, &rec->size[recInfo_filename]);
 
-#if SU_SCHEME
+    /* update delete keys */
+    xfree (rec->info[recInfo_delKeys]);
+    if (zh->keys.buf_used > 0 && rGroup->flagStoreKeys == 1)
+    {
+#if 1
+        rec->size[recInfo_delKeys] = zh->keys.buf_used;
+        rec->info[recInfo_delKeys] = zh->keys.buf;
+        zh->keys.buf = NULL;
+        zh->keys.buf_max = 0;
 #else
-        ch = zebraExplain_lookupSU (zti, attrSet, attrUse);
-        if (ch < 0)
-        {
-            ch = zebraExplain_addSU (zti, attrSet, attrUse);
-            yaz_log (LOG_LOG, "addSU cmd=%d set=%d use=%d SU=%d",
-                     cmd, attrSet, attrUse, ch);
-        }
+        rec->info[recInfo_delKeys] = xmalloc (reckeys.buf_used);
+        rec->size[recInfo_delKeys] = reckeys.buf_used;
+        memcpy (rec->info[recInfo_delKeys], reckeys.buf,
+                rec->size[recInfo_delKeys]);
 #endif
-        assert (ch > 0);
-       key_buf_used += key_SU_encode (ch, ((char*)key_buf) + key_buf_used);
+    }
+    else
+    {
+        rec->info[recInfo_delKeys] = NULL;
+        rec->size[recInfo_delKeys] = 0;
+    }
 
-        while (*src)
-            ((char*)key_buf) [key_buf_used++] = *src++;
-        src++;
-        ((char*)key_buf) [key_buf_used++] = '\0';
-        ((char*) key_buf)[key_buf_used++] = cmd;
+    /* save file size of original record */
+    zebraExplain_recordBytesIncrement (zh->service->zei,
+                                       - recordAttr->recordSize);
+    recordAttr->recordSize = fi->file_moffset - recordOffset;
+    if (!recordAttr->recordSize)
+       recordAttr->recordSize = fi->file_max - recordOffset;
+    zebraExplain_recordBytesIncrement (zh->service->zei,
+                                       recordAttr->recordSize);
 
-        if (lead & 60)
-            seqno += ((lead>>2) & 15)-1;
-        else
+    /* set run-number for this record */
+    recordAttr->runNumber = zebraExplain_runNumberIncrement (zh->service->zei,
+                                                             0);
+
+    /* update store data */
+    xfree (rec->info[recInfo_storeData]);
+    if (rGroup->flagStoreData == 1)
+    {
+        rec->size[recInfo_storeData] = recordAttr->recordSize;
+        rec->info[recInfo_storeData] = (char *)
+           xmalloc (recordAttr->recordSize);
+        if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
         {
-            memcpy (&seqno, src, sizeof(seqno));
-            src += sizeof(seqno);
+            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);
         }
-        key.seqno = seqno;
-        key.sysno = sysno;
-        memcpy ((char*)key_buf + key_buf_used, &key, sizeof(key));
-        key_buf_used += sizeof(key);
-        off = src - reckeys->buf;
     }
-    assert (off == reckeys->buf_used);
+    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 (rGroup->databaseName, &rec->size[recInfo_databaseName]); 
+
+    /* update offset */
+    recordAttr->recordOffset = recordOffset;
+    
+    /* commit this record */
+    rec_put (zh->service->records, &rec);
+    logRecord (0);
+    return 1;
 }
 
-static const char **searchRecordKey (struct recKeys *reckeys,
-                                    int attrSetS, int attrUseS)
+int fileExtract (ZebraHandle zh, SYSNO *sysno, const char *fname, 
+                 const struct recordGroup *rGroupP, int deleteFlag)
 {
-    static const char *ws[32];
-    int off = 0;
-    int startSeq = -1;
-    int i;
-    int seqno = 0;
-#if SU_SCHEME
-    int chS, ch;
-#else
-    short attrUse;
-    char attrSet;
-#endif
+    int r, i, fd;
+    char gprefix[128];
+    char ext[128];
+    char ext_res[128];
+    char subType[128];
+    RecType recType;
+    struct recordGroup rGroupM;
+    struct recordGroup *rGroup = &rGroupM;
+    struct file_read_info *fi;
+    void *clientData;
 
-    for (i = 0; i<32; i++)
-        ws[i] = NULL;
+    memcpy (rGroup, rGroupP, sizeof(*rGroupP));
+   
+    if (!rGroup->groupName || !*rGroup->groupName)
+        *gprefix = '\0';
+    else
+        sprintf (gprefix, "%s.", rGroup->groupName);
 
-#if SU_SCHEME
-    chS = zebraExplain_lookupSU (zti, attrSetS, attrUseS);
-    if (chS < 0)
-       return ws;
-#endif
-    while (off < reckeys->buf_used)
-    {
+    logf (LOG_DEBUG, "fileExtract %s", fname);
 
-        const char *src = reckeys->buf + off;
-       const char *wstart;
-        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))
+    /* determine file extension */
+    *ext = '\0';
+    for (i = strlen(fname); --i >= 0; )
+        if (fname[i] == '/')
+            break;
+        else if (fname[i] == '.')
         {
-            memcpy (&attrUse, src, sizeof(attrUse));
-            src += sizeof(attrUse);
+            strcpy (ext, fname+i+1);
+            break;
         }
-#endif
-        wstart = src;
-        while (*src++)
-            ;
-        if (lead & 60)
-            seqno += ((lead>>2) & 15)-1;
-        else
+    /* determine file type - depending on extension */
+    if (!rGroup->recordType)
+    {
+        sprintf (ext_res, "%srecordType.%s", gprefix, ext);
+        if (!(rGroup->recordType = res_get (zh->service->res, ext_res)))
         {
-            memcpy (&seqno, src, sizeof(seqno));
-            src += sizeof(seqno);
+            sprintf (ext_res, "%srecordType", gprefix);
+            rGroup->recordType = res_get (zh->service->res, ext_res);
         }
-       if (
-#if SU_SCHEME
-           ch == chS
-#else
-           attrUseS == attrUse && attrSetS == attrSet
-#endif
-           )
-        {
-            int woff;
+    }
+    if (!rGroup->recordType)
+    {
+        if (records_processed < rGroup->fileVerboseLimit)
+            logf (LOG_LOG, "? %s", fname);
+        return 0;
+    }
+    if (!*rGroup->recordType)
+       return 0;
+    if (!(recType =
+         recType_byName (zh->service->recTypes, rGroup->recordType, subType,
+                         &clientData)))
+    {
+        logf (LOG_WARN, "No such record type: %s", rGroup->recordType);
+        return 0;
+    }
 
+    /* determine match criteria */
+    if (!rGroup->recordId)
+    {
+        sprintf (ext_res, "%srecordId.%s", gprefix, ext);
+        rGroup->recordId = res_get (zh->service->res, ext_res);
+    }
 
-            if (startSeq == -1)
-                startSeq = seqno;
-            woff = seqno - startSeq;
-            if (woff >= 0 && woff < 31)
-                ws[woff] = wstart;
+    /* determine database name */
+    if (!rGroup->databaseName)
+    {
+        sprintf (ext_res, "%sdatabase.%s", gprefix, ext);
+        if (!(rGroup->databaseName = res_get (zh->service->res, ext_res)))
+        {
+            sprintf (ext_res, "%sdatabase", gprefix);
+            rGroup->databaseName = res_get (zh->service->res, ext_res);
         }
-
-        off = src - reckeys->buf;
     }
-    assert (off == reckeys->buf_used);
-    return ws;
-}
-
-struct file_read_info {
-    off_t file_max;        /* maximum offset so far */
-    off_t file_offset;      /* current offset */
-    off_t file_moffset;     /* offset of rec/rec boundary */
-    int file_more;
-    int fd;
-    char *sdrbuf;
-    int sdrmax;
-};
-
-static struct file_read_info *file_read_start (int fd)
-{
-    struct file_read_info *fi = (struct file_read_info *)
-       xmalloc (sizeof(*fi));
-
-    fi->fd = fd;
-    fi->file_max = 0;
-    fi->file_moffset = 0;
-    fi->sdrbuf = 0;
-    fi->sdrmax = 0;
-    return fi;
-}
-
-static void file_read_stop (struct file_read_info *fi)
-{
-    xfree (fi);
-}
+    if (!rGroup->databaseName)
+        rGroup->databaseName = "Default";
 
-static off_t file_seek (void *handle, off_t offset)
-{
-    struct file_read_info *p = (struct file_read_info *) handle;
-    p->file_offset = offset;
-    if (p->sdrbuf)
-       return offset;
-    return lseek (p->fd, offset, SEEK_SET);
-}
+    /* determine if explain database */
+    
+    sprintf (ext_res, "%sexplainDatabase", gprefix);
+    rGroup->explainDatabase =
+       atoi (res_get_def (zh->service->res, ext_res, "0"));
 
-static off_t file_tell (void *handle)
-{
-    struct file_read_info *p = (struct file_read_info *) handle;
-    return p->file_offset;
-}
+    /* announce database */
+    if (zebraExplain_curDatabase (zh->service->zei, rGroup->databaseName))
+    {
+        if (zebraExplain_newDatabase (zh->service->zei, rGroup->databaseName,
+                                     rGroup->explainDatabase))
+           return 0;
+    }
 
-static int file_read (void *handle, char *buf, size_t count)
-{
-    struct file_read_info *p = (struct file_read_info *) handle;
-    int fd = p->fd;
-    int r;
-    if (p->sdrbuf)
+    if (rGroup->flagStoreData == -1)
     {
-       r = count;
-       if (r > p->sdrmax - p->file_offset)
-           r = p->sdrmax - p->file_offset;
-       if (r)
-           memcpy (buf, p->sdrbuf + p->file_offset, r);
+        const char *sval;
+        sprintf (ext_res, "%sstoreData.%s", gprefix, ext);
+        if (!(sval = res_get (zh->service->res, ext_res)))
+        {
+            sprintf (ext_res, "%sstoreData", gprefix);
+            sval = res_get (zh->service->res, ext_res);
+        }
+        if (sval)
+            rGroup->flagStoreData = atoi (sval);
+    }
+    if (rGroup->flagStoreData == -1)
+        rGroup->flagStoreData = 0;
+
+    if (rGroup->flagStoreKeys == -1)
+    {
+        const char *sval;
+
+        sprintf (ext_res, "%sstoreKeys.%s", gprefix, ext);
+        sval = res_get (zh->service->res, ext_res);
+       if (!sval)
+        {
+            sprintf (ext_res, "%sstoreKeys", gprefix);
+            sval = res_get (zh->service->res, ext_res);
+        }
+       if (!sval)
+           sval = res_get (zh->service->res, "storeKeys");
+        if (sval)
+            rGroup->flagStoreKeys = atoi (sval);
     }
+    if (rGroup->flagStoreKeys == -1)
+        rGroup->flagStoreKeys = 0;
+
+    if (sysno && deleteFlag)
+        fd = -1;
     else
-       r = read (fd, buf, count);
-    if (r > 0)
     {
-        p->file_offset += r;
-        if (p->file_offset > p->file_max)
-            p->file_max = p->file_offset;
+        if ((fd = open (fname, O_BINARY|O_RDONLY)) == -1)
+        {
+            logf (LOG_WARN|LOG_ERRNO, "open %s", fname);
+            return 0;
+        }
     }
+    fi = file_read_start (fd);
+    do
+    {
+        file_begin (fi);
+        r = recordExtract (zh, sysno, fname, rGroup, deleteFlag, fi,
+                           recType, subType, clientData);
+    } while (r && !sysno && fi->file_more);
+    file_read_stop (fi);
+    if (fd != -1)
+        close (fd);
     return r;
 }
 
-static void file_begin (void *handle)
+
+int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
+                        const char *buf, size_t buf_size,
+                        const char *databaseName, int delete_flag,
+                        int test_mode, int *sysno,
+                        int store_keys, int store_data,
+                        const char *match_criteria)
 {
-    struct file_read_info *p = (struct file_read_info *) handle;
+    RecordAttr *recordAttr;
+    struct recExtractCtrl extractCtrl;
+    int i, r;
+    char *matchStr;
+    RecType recType;
+    char subType[1024];
+    void *clientData;
+    const char *fname = "<no file>";
+    Record rec;
+    long recordOffset = 0;
+    struct zebra_fetch_control fc;
+
+    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;
 
-    p->file_offset = p->file_moffset;
-    if (!p->sdrbuf && p->file_moffset)
-        lseek (p->fd, p->file_moffset, SEEK_SET);
-    p->file_more = 0;
-}
+    /* announce database */
+    if (zebraExplain_curDatabase (zh->service->zei, databaseName))
+    {
+        if (zebraExplain_newDatabase (zh->service->zei, databaseName, 0))
+           return 0;
+    }
+    if (!(recType =
+         recType_byName (zh->service->recTypes, recordType, subType,
+                         &clientData)))
+    {
+        logf (LOG_WARN, "No such record type: %s", recordType);
+        return 0;
+    }
 
-static void file_end (void *handle, off_t offset)
-{
-    struct file_read_info *p = (struct file_read_info *) handle;
+    zh->keys.buf_used = 0;
+    zh->keys.prevAttrUse = -1;
+    zh->keys.prevAttrSet = -1;
+    zh->keys.prevSeqNo = 0;
+    zh->sortKeys = 0;
+
+    extractCtrl.subType = subType;
+    extractCtrl.init = extract_init;
+    extractCtrl.tokenAdd = extract_token_add;
+    extractCtrl.schemaAdd = extract_schema_add;
+    extractCtrl.dh = zh->service->dh;
+    extractCtrl.handle = zh;
+    extractCtrl.zebra_maps = zh->service->zebra_maps;
+    extractCtrl.flagShowRecords = 0;
+    for (i = 0; i<256; i++)
+    {
+       if (zebra_maps_is_positioned(zh->service->zebra_maps, i))
+           extractCtrl.seqno[i] = 1;
+       else
+           extractCtrl.seqno[i] = 0;
+    }
 
-    assert (p->file_more == 0);
-    p->file_more = 1;
-    p->file_moffset = offset;
-}
+    r = (*recType->extract)(clientData, &extractCtrl);
 
-static char *fileMatchStr (struct recKeys *reckeys, struct recordGroup *rGroup,
-                           const char *fname, const char *spec)
-{
-    static char dstBuf[2048];
-    char *dst = dstBuf;
-    const char *s = spec;
-    static const char **w;
+    if (r == RECCTRL_EXTRACT_EOF)
+       return 0;
+    else if (r == RECCTRL_EXTRACT_ERROR)
+    {
+       /* error occured during extraction ... */
+#if 1
+       yaz_log (LOG_WARN, "extract error");
+#else
+       if (rGroup->flagRw &&
+           records_processed < rGroup->fileVerboseLimit)
+       {
+           logf (LOG_WARN, "fail %s %s %ld", rGroup->recordType,
+                 fname, (long) recordOffset);
+       }
+#endif
+       return 0;
+    }
+    if (zh->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 */
 
-    while (1)
+
+    if (! *sysno)
     {
-        while (*s == ' ' || *s == '\t')
-            s++;
-        if (!*s)
-            break;
-        if (*s == '(')
+        /* new record */
+        if (delete_flag)
         {
-           char attset_str[64], attname_str[64];
-           data1_attset *attset;
-           int i;
-            char matchFlag[32];
-            int attSet = 1, attUse = 1;
-            int first = 1;
+           logf (LOG_LOG, "delete %s %s %ld", recordType,
+                 fname, (long) recordOffset);
+            logf (LOG_WARN, "cannot delete record above (seems new)");
+            return 1;
+        }
+       logf (LOG_LOG, "add %s %s %ld", recordType, fname,
+             (long) recordOffset);
+        rec = rec_new (zh->service->records);
 
-            s++;
-           for (i = 0; *s && *s != ',' && *s != ')'; s++)
-               if (i < 63)
-                   attset_str[i++] = *s;
-           attset_str[i] = '\0';
+        *sysno = rec->sysno;
 
-           if (*s == ',')
-           {
-               s++;
-               for (i = 0; *s && *s != ')'; s++)
-                   if (i < 63)
-                       attname_str[i++] = *s;
-               attname_str[i] = '\0';
-           }
-           
-           if ((attset = data1_get_attset (rGroup->dh, attset_str)))
-           {
-               data1_att *att;
-               attSet = attset->reference;
-               att = data1_getattbyname(rGroup->dh, attset, attname_str);
-               if (att)
-                   attUse = att->value;
-               else
-                   attUse = atoi (attname_str);
-           }
-            w = searchRecordKey (reckeys, attSet, attUse);
-            assert (w);
+       recordAttr = rec_init_attr (zh->service->zei, rec);
 
-            if (*s == ')')
+        if (matchStr)
+        {
+            dict_insert (zh->service->matchDict, matchStr,
+                         sizeof(*sysno), sysno);
+        }
+        extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
+       extract_flushSortKeys (zh, *sysno, 1, &zh->sortKeys);
+    }
+    else
+    {
+        /* record already exists */
+        struct recKeys delkeys;
+
+        rec = rec_get (zh->service->records, *sysno);
+        assert (rec);
+       
+       recordAttr = rec_init_attr (zh->service->zei, rec);
+
+       if (recordAttr->runNumber ==
+           zebraExplain_runNumberIncrement (zh->service->zei, 0))
+       {
+           logf (LOG_LOG, "skipped %s %s %ld", recordType,
+                 fname, (long) recordOffset);
+           rec_rm (&rec);
+           return 1;
+       }
+        delkeys.buf_used = rec->size[recInfo_delKeys];
+       delkeys.buf = rec->info[recInfo_delKeys];
+       extract_flushSortKeys (zh, *sysno, 0, &zh->sortKeys);
+        extract_flushRecordKeys (zh, *sysno, 0, &delkeys);
+        if (delete_flag)
+        {
+            /* record going to be deleted */
+            if (!delkeys.buf_used)
             {
-                for (i = 0; i<32; i++)
-                    matchFlag[i] = 1;
+                logf (LOG_LOG, "delete %s %s %ld", recordType,
+                      fname, (long) recordOffset);
+                logf (LOG_WARN, "cannot delete file above, storeKeys false");
             }
             else
             {
-                logf (LOG_WARN, "Missing ) in match criteria %s in group %s",
-                      spec, rGroup->groupName ? rGroup->groupName : "none");
-                return NULL;
-            }
-            s++;
-
-            for (i = 0; i<32; i++)
-                if (matchFlag[i] && w[i])
-                {
-                    if (first)
-                    {
-                        *dst++ = ' ';
-                        first = 0;
-                    }
-                    strcpy (dst, w[i]);
-                    dst += strlen(w[i]);
-                }
-            if (first)
-            {
-                logf (LOG_WARN, "Record didn't contain match"
-                      " fields in (%s,%s)", attset_str, attname_str);
-                return NULL;
+               logf (LOG_LOG, "delete %s %s %ld", recordType,
+                     fname, (long) recordOffset);
+#if 0
+                if (matchStr)
+                    dict_delete (matchDict, matchStr);
+#endif
+                rec_del (zh->service->records, &rec);
             }
+           rec_rm (&rec);
+            return 1;
         }
-        else if (*s == '$')
+        else
         {
-            int spec_len;
-            char special[64];
-            const char *spec_src = NULL;
-            const char *s1 = ++s;
-            while (*s1 && *s1 != ' ' && *s1 != '\t')
-                s1++;
-
-            spec_len = s1 - s;
-            if (spec_len > 63)
-                spec_len = 63;
-            memcpy (special, s, spec_len);
-            special[spec_len] = '\0';
-            s = s1;
-
-            if (!strcmp (special, "group"))
-                spec_src = rGroup->groupName;
-            else if (!strcmp (special, "database"))
-                spec_src = rGroup->databaseName;
-            else if (!strcmp (special, "filename"))
-                spec_src = fname;
-            else if (!strcmp (special, "type"))
-                spec_src = rGroup->recordType;
-            else 
-                spec_src = NULL;
-            if (spec_src)
+            /* record going to be updated */
+            if (!delkeys.buf_used)
             {
-                strcpy (dst, spec_src);
-                dst += strlen (spec_src);
+                logf (LOG_LOG, "update %s %s %ld", recordType,
+                      fname, (long) recordOffset);
+                logf (LOG_WARN, "cannot update file above, storeKeys false");
+            }
+            else
+            {
+               logf (LOG_LOG, "update %s %s %ld", recordType,
+                     fname, (long) recordOffset);
+                extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
             }
         }
-        else if (*s == '\"' || *s == '\'')
-        {
-            int stopMarker = *s++;
-            char tmpString[64];
-            int i = 0;
+    }
+    /* 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->keys.buf_used > 0 && store_keys == 1)
+    {
+        rec->size[recInfo_delKeys] = zh->keys.buf_used;
+        rec->info[recInfo_delKeys] = zh->keys.buf;
+        zh->keys.buf = NULL;
+        zh->keys.buf_max = 0;
+    }
+    else
+    {
+        rec->info[recInfo_delKeys] = NULL;
+        rec->size[recInfo_delKeys] = 0;
+    }
 
-            while (*s && *s != stopMarker)
-            {
-                if (i < 63)
-                    tmpString[i++] = *s++;
-            }
-            if (*s)
-                s++;
-            tmpString[i] = '\0';
-            strcpy (dst, tmpString);
-            dst += strlen (tmpString);
+    /* save file size of original record */
+    zebraExplain_recordBytesIncrement (zh->service->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->service->zei,
+                                      recordAttr->recordSize);
+
+    /* set run-number for this record */
+    recordAttr->runNumber =
+       zebraExplain_runNumberIncrement (zh->service->zei, 0);
+
+    /* update store data */
+    xfree (rec->info[recInfo_storeData]);
+    if (store_data == 1)
+    {
+        rec->size[recInfo_storeData] = recordAttr->recordSize;
+        rec->info[recInfo_storeData] = (char *)
+           xmalloc (recordAttr->recordSize);
+#if 1
+        memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
+#else
+        if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
+        {
+            logf (LOG_ERRNO|LOG_FATAL, "seek to %ld in %s",
+                  (long) recordOffset, fname);
+            exit (1);
         }
-        else
+        if (read (fi->fd, rec->info[recInfo_storeData], recordAttr->recordSize)
+           < recordAttr->recordSize)
         {
-            logf (LOG_WARN, "Syntax error in match criteria %s in group %s",
-                  spec, rGroup->groupName ? rGroup->groupName : "none");
-            return NULL;
+            logf (LOG_ERRNO|LOG_FATAL, "read %d bytes of %s",
+                  recordAttr->recordSize, fname);
+            exit (1);
         }
-        *dst++ = 1;
+#endif
     }
-    if (dst == dstBuf)
+    else
     {
-        logf (LOG_WARN, "No match criteria for record %s in group %s",
-              fname, rGroup->groupName ? rGroup->groupName : "none");
-        return NULL;
+        rec->info[recInfo_storeData] = NULL;
+        rec->size[recInfo_storeData] = 0;
     }
-    *dst = '\0';
-    return dstBuf;
-}
-
-struct recordLogInfo {
-    const char *fname;
-    int recordOffset;
-    struct recordGroup *rGroup;
-};
-     
-static void recordLogPreamble (int level, const char *msg, void *info)
-{
-    struct recordLogInfo *p = (struct recordLogInfo *) info;
-    FILE *outf = yaz_log_file ();
+    /* update database name */
+    xfree (rec->info[recInfo_databaseName]);
+    rec->info[recInfo_databaseName] =
+        rec_strdup (databaseName, &rec->size[recInfo_databaseName]); 
 
-    if (level & LOG_LOG)
-        return ;
-    fprintf (outf, "File %s, offset %d, type %s\n",
-             p->rGroup->recordType, p->recordOffset, p->fname);
-    log_event_start (NULL, NULL);
-}
+    /* update offset */
+    recordAttr->recordOffset = recordOffset;
+    
+    /* commit this record */
+    rec_put (zh->service->records, &rec);
 
-void addSchema (struct recExtractCtrl *p, Odr_oid *oid)
-{
-    zebraExplain_addSchema (zti, oid);
+    return 0;
 }
 
-static int recordExtract (SYSNO *sysno, const char *fname,
-                          struct recordGroup *rGroup, int deleteFlag,
-                          struct file_read_info *fi,
-                         RecType recType, char *subType, void *clientData)
+int explain_extract (void *handle, Record rec, data1_node *n)
 {
-    RecordAttr *recordAttr;
-    int r;
-    char *matchStr;
-    SYSNO sysnotmp;
-    Record rec;
-    struct recordLogInfo logInfo;
-    off_t recordOffset = 0;
+    ZebraHandle zh = (ZebraHandle) handle;
+    struct recExtractCtrl extractCtrl;
+    int i;
 
-    if (fi->fd != -1)
+    if (zebraExplain_curDatabase (zh->service->zei,
+                                 rec->info[recInfo_databaseName]))
     {
-       struct recExtractCtrl extractCtrl;
+       abort();
+        if (zebraExplain_newDatabase (zh->service->zei,
+                                     rec->info[recInfo_databaseName], 0))
+            abort ();
+    }
 
-        /* we are going to read from a file, so prepare the extraction */
-       int i;
+    zh->keys.buf_used = 0;
+    zh->keys.prevAttrUse = -1;
+    zh->keys.prevAttrSet = -1;
+    zh->keys.prevSeqNo = 0;
+    zh->sortKeys = 0;
+    
+    extractCtrl.init = extract_init;
+    extractCtrl.tokenAdd = extract_token_add;
+    extractCtrl.schemaAdd = extract_schema_add;
+    extractCtrl.dh = zh->service->dh;
+    for (i = 0; i<256; i++)
+       extractCtrl.seqno[i] = 0;
+    extractCtrl.zebra_maps = zh->service->zebra_maps;
+    extractCtrl.flagShowRecords = 0;
+    extractCtrl.handle = handle;
+    
+    grs_extract_tree(&extractCtrl, n);
 
-       reckeys.buf_used = 0;
-       reckeys.prevAttrUse = -1;
-       reckeys.prevAttrSet = -1;
-       reckeys.prevSeqNo = 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 = wordInit;
-       extractCtrl.tokenAdd = addRecordKey;
-       extractCtrl.schemaAdd = addSchema;
-       extractCtrl.dh = rGroup->dh;
-       for (i = 0; i<256; i++)
-       {
-           if (zebra_maps_is_positioned(rGroup->zebra_maps, i))
-               extractCtrl.seqno[i] = 1;
-           else
-               extractCtrl.seqno[i] = 0;
-       }
-       extractCtrl.zebra_maps = rGroup->zebra_maps;
-       extractCtrl.flagShowRecords = !rGroup->flagRw;
+    logf (LOG_LOG, "flush explain record, sysno=%d", rec->sysno);
 
-        if (!rGroup->flagRw)
-            printf ("File: %s " PRINTF_OFF_T "\n", fname, recordOffset);
+    if (rec->size[recInfo_delKeys])
+    {
+       struct recKeys delkeys;
+       struct sortKey *sortKeys = 0;
 
-        logInfo.fname = fname;
-        logInfo.recordOffset = recordOffset;
-        logInfo.rGroup = rGroup;
-        log_event_start (recordLogPreamble, &logInfo);
+       delkeys.buf_used = rec->size[recInfo_delKeys];
+       delkeys.buf = rec->info[recInfo_delKeys];
+       extract_flushSortKeys (zh, rec->sysno, 0, &sortKeys);
+       extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
+    }
+    extract_flushRecordKeys (zh, rec->sysno, 1, &zh->keys);
+    extract_flushSortKeys (zh, rec->sysno, 1, &zh->sortKeys);
 
-        r = (*recType->extract)(clientData, &extractCtrl);
+    xfree (rec->info[recInfo_delKeys]);
+    rec->size[recInfo_delKeys] = zh->keys.buf_used;
+    rec->info[recInfo_delKeys] = zh->keys.buf;
+    zh->keys.buf = NULL;
+    zh->keys.buf_max = 0;
+    return 0;
+}
 
-        log_event_start (NULL, NULL);
+void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
+                              int cmd, struct recKeys *reckeys)
+{
+#if SU_SCHEME
+#else
+    unsigned char attrSet = (unsigned char) -1;
+    unsigned short attrUse = (unsigned short) -1;
+#endif
+    int seqno = 0;
+    int off = 0;
+    int ch = 0;
+    ZebraExplainInfo zei = zh->service->zei;
 
-       if (r == RECCTRL_EXTRACT_EOF)
-           return 0;
-       else if (r == RECCTRL_EXTRACT_ERROR)
+    if (!zh->key_buf)
+    {
+       int mem = 8*1024*1024;
+       zh->key_buf = (char**) xmalloc (mem);
+       zh->ptr_top = mem/sizeof(char*);
+       zh->ptr_i = 0;
+       zh->key_buf_used = 0;
+       zh->key_file_no = 0;
+    }
+    zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
+    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)
        {
-            /* error occured during extraction ... */
-            if (rGroup->flagRw &&
-               records_processed < rGroup->fileVerboseLimit)
-            {
-                logf (LOG_WARN, "fail %s %s " PRINTF_OFF_T, rGroup->recordType,
-                      fname, recordOffset);
-            }
-            return 0;
-        }
-        if (reckeys.buf_used == 0)
+           memcpy (&ch, src, sizeof(ch));
+           src += sizeof(ch);
+       }
+#else
+        if (!(lead & 1))
         {
-            /* the extraction process returned no information - the record
-               is probably empty - unless flagShowRecords is in use */
-            if (!rGroup->flagRw)
-                return 1;
-           
-           logf (LOG_WARN, "empty %s %s " PRINTF_OFF_T, rGroup->recordType,
-                 fname, recordOffset);
-            return 1;
+            memcpy (&attrSet, src, sizeof(attrSet));
+            src += sizeof(attrSet);
         }
-    }
-
-    /* perform match if sysno not known and if match criteria is specified */
-       
-    matchStr = NULL;
-    if (!sysno) 
-    {
-        sysnotmp = 0;
-        sysno = &sysnotmp;
-        if (rGroup->recordId && *rGroup->recordId)
+        if (!(lead & 2))
         {
-            char *rinfo;
-        
-            matchStr = fileMatchStr (&reckeys, rGroup, fname, 
-                                     rGroup->recordId);
-            if (matchStr)
-            {
-                rinfo = dict_lookup (matchDict, matchStr);
-                if (rinfo)
-                    memcpy (sysno, rinfo+1, sizeof(*sysno));
-            }
-            else
-            {
-                logf (LOG_WARN, "Bad match criteria");
-                return 0;
-            }
+            memcpy (&attrUse, src, sizeof(attrUse));
+            src += sizeof(attrUse);
         }
-    }
+#endif
+        if (zh->key_buf_used + 1024 > (zh->ptr_top-zh->ptr_i)*sizeof(char*))
+            extract_flushWriteKeys (zh);
+        ++(zh->ptr_i);
+        (zh->key_buf)[zh->ptr_top - zh->ptr_i] =
+           (char*)zh->key_buf + zh->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->key_buf_used +=
+           key_SU_encode (ch,((char*)zh->key_buf) + zh->key_buf_used);
 
-    if (! *sysno)
-    {
-        /* new record */
-        if (deleteFlag)
+        while (*src)
+            ((char*)zh->key_buf) [(zh->key_buf_used)++] = *src++;
+        src++;
+        ((char*)(zh->key_buf))[(zh->key_buf_used)++] = '\0';
+        ((char*)(zh->key_buf))[(zh->key_buf_used)++] = cmd;
+
+        if (lead & 60)
+            seqno += ((lead>>2) & 15)-1;
+        else
         {
-           logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T, rGroup->recordType,
-                 fname, recordOffset);
-            logf (LOG_WARN, "cannot delete record above (seems new)");
-            return 1;
+            memcpy (&seqno, src, sizeof(seqno));
+            src += sizeof(seqno);
         }
-        if (records_processed < rGroup->fileVerboseLimit)
-            logf (LOG_LOG, "add %s %s " PRINTF_OFF_T, rGroup->recordType,
-                  fname, recordOffset);
-        rec = rec_new (records);
-
-        *sysno = rec->sysno;
+        key.seqno = seqno;
+        key.sysno = sysno;
+        memcpy ((char*)zh->key_buf + zh->key_buf_used, &key, sizeof(key));
+        (zh->key_buf_used) += sizeof(key);
+        off = src - reckeys->buf;
+    }
+    assert (off == reckeys->buf_used);
+}
 
-       recordAttr = rec_init_attr (zti, rec);
+void extract_flushWriteKeys (ZebraHandle zh)
+{
+    FILE *outf;
+    char out_fname[200];
+    char *prevcp, *cp;
+    struct encode_info encode_info;
+    int ptr_i = zh->ptr_i;
+#if SORT_EXTRA
+    int i;
+#endif
+    if (!zh->key_buf || ptr_i <= 0)
+        return;
 
-        if (matchStr)
-        {
-            dict_insert (matchDict, matchStr, sizeof(*sysno), sysno);
-        }
-        flushRecordKeys (*sysno, 1, &reckeys);
-       flushSortKeys (*sysno, 1);
+    (zh->key_file_no)++;
+    logf (LOG_LOG, "sorting section %d", (zh->key_file_no));
+#if !SORT_EXTRA
+    qsort (zh->key_buf + zh->ptr_top - ptr_i, ptr_i, sizeof(char*),
+           key_qsort_compare);
+    extract_get_fname_tmp (zh, out_fname, zh->key_file_no);
 
-        records_inserted++;
+    if (!(outf = fopen (out_fname, "wb")))
+    {
+        logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
+        exit (1);
     }
-    else
+    logf (LOG_LOG, "writing section %d", zh->key_file_no);
+    prevcp = cp = (zh->key_buf)[zh->ptr_top - ptr_i];
+    
+    encode_key_init (&encode_info);
+    encode_key_write (cp, &encode_info, outf);
+    
+    while (--ptr_i > 0)
     {
-        /* record already exists */
-        struct recKeys delkeys;
-
-        rec = rec_get (records, *sysno);
-        assert (rec);
-       
-       recordAttr = rec_init_attr (zti, rec);
-
-       if (recordAttr->runNumber == zebraExplain_runNumberIncrement (zti, 0))
-       {
-           logf (LOG_LOG, "skipped %s %s " PRINTF_OFF_T, rGroup->recordType,
-                 fname, recordOffset);
-           flushSortKeys (*sysno, -1);
-           rec_rm (&rec);
-           logRecord (0);
-           return 1;
-       }
-        delkeys.buf_used = rec->size[recInfo_delKeys];
-       delkeys.buf = rec->info[recInfo_delKeys];
-       flushSortKeys (*sysno, 0);
-        flushRecordKeys (*sysno, 0, &delkeys);
-        if (deleteFlag)
+        cp = (zh->key_buf)[zh->ptr_top - ptr_i];
+        if (strcmp (cp, prevcp))
         {
-            /* record going to be deleted */
-            if (!delkeys.buf_used)
-            {
-                logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
-                      rGroup->recordType, fname, recordOffset);
-                logf (LOG_WARN, "cannot delete file above, storeKeys false");
-            }
-            else
-            {
-                if (records_processed < rGroup->fileVerboseLimit)
-                    logf (LOG_LOG, "delete %s %s " PRINTF_OFF_T,
-                         rGroup->recordType, fname, recordOffset);
-                records_deleted++;
-                if (matchStr)
-                    dict_delete (matchDict, matchStr);
-                rec_del (records, &rec);
-            }
-           rec_rm (&rec);
-            logRecord (0);
-            return 1;
+            encode_key_init (&encode_info);
+            encode_key_write (cp, &encode_info, outf);
+            prevcp = cp;
         }
         else
+            encode_key_write (cp + strlen(cp), &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]))
         {
-            /* record going to be updated */
-            if (!delkeys.buf_used)
-            {
-                logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
-                      rGroup->recordType, fname, recordOffset);
-                logf (LOG_WARN, "cannot update file above, storeKeys false");
-            }
-            else
+            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)
             {
-                if (records_processed < rGroup->fileVerboseLimit)
-                    logf (LOG_LOG, "update %s %s " PRINTF_OFF_T,
-                        rGroup->recordType, fname, recordOffset);
-                flushRecordKeys (*sysno, 1, &reckeys);
-                records_updated++;
+                cp = key_buf[ptr_top-ptr_i];
+                encode_key_write (cp+key_y_len, &encode_info, outf);
             }
+            if (!i)
+                break;
+            prevcp = key_buf[ptr_top-ptr_i];
         }
+#endif
+    if (fclose (outf))
+    {
+        logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
+        exit (1);
     }
-    /* update file type */
-    xfree (rec->info[recInfo_fileType]);
-    rec->info[recInfo_fileType] =
-        rec_strdup (rGroup->recordType, &rec->size[recInfo_fileType]);
+    logf (LOG_LOG, "finished section %d", zh->key_file_no);
+    zh->ptr_i = 0;
+    zh->key_buf_used = 0;
+}
 
-    /* update filename */
-    xfree (rec->info[recInfo_filename]);
-    rec->info[recInfo_filename] =
-        rec_strdup (fname, &rec->size[recInfo_filename]);
+void extract_add_index_string (RecWord *p, const char *string,
+                               int length)
+{
+    char *dst;
+    unsigned char attrSet;
+    unsigned short attrUse;
+    int lead = 0;
+    int diff = 0;
+    int *pseqno = &p->seqnos[p->reg_type];
+    ZebraHandle zh = p->extractCtrl->handle;
+    ZebraExplainInfo zei = zh->service->zei;
+    struct recKeys *keys = &zh->keys;
 
-    /* update delete keys */
-    xfree (rec->info[recInfo_delKeys]);
-    if (reckeys.buf_used > 0 && rGroup->flagStoreKeys == 1)
+    if (keys->buf_used+1024 > keys->buf_max)
     {
+        char *b;
+
+        b = (char *) xmalloc (keys->buf_max += 128000);
+        if (keys->buf_used > 0)
+            memcpy (b, keys->buf, keys->buf_used);
+        xfree (keys->buf);
+        keys->buf = b;
+    }
+    dst = keys->buf + keys->buf_used;
+
+    attrSet = p->attrSet;
+    if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
+        lead |= 1;
+    else
+        keys->prevAttrSet = attrSet;
+    attrUse = p->attrUse;
+    if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
+        lead |= 2;
+    else
+        keys->prevAttrUse = attrUse;
 #if 1
-        rec->size[recInfo_delKeys] = reckeys.buf_used;
-        rec->info[recInfo_delKeys] = reckeys.buf;
-        reckeys.buf = NULL;
-        reckeys.buf_max = 0;
-#else
-        rec->info[recInfo_delKeys] = xmalloc (reckeys.buf_used);
-        rec->size[recInfo_delKeys] = reckeys.buf_used;
-        memcpy (rec->info[recInfo_delKeys], reckeys.buf,
-                rec->size[recInfo_delKeys]);
+    diff = 1 + *pseqno - keys->prevSeqNo;
+    if (diff >= 1 && diff <= 15)
+        lead |= (diff << 2);
+    else
+        diff = 0;
 #endif
+    keys->prevSeqNo = *pseqno;
+    
+    *dst++ = lead;
+
+#if SU_SCHEME
+    if ((lead & 3) < 3)
+    {
+        int ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
+        if (ch < 0)
+        {
+            ch = zebraExplain_addSU (zei, attrSet, attrUse);
+            yaz_log (LOG_LOG, "addSU set=%d use=%d SU=%d",
+                     attrSet, attrUse, ch);
+        }
+       assert (ch > 0);
+       memcpy (dst, &ch, sizeof(ch));
+       dst += sizeof(ch);
     }
-    else
+#else
+    if (!(lead & 1))
     {
-        rec->info[recInfo_delKeys] = NULL;
-        rec->size[recInfo_delKeys] = 0;
+        memcpy (dst, &attrSet, sizeof(attrSet));
+        dst += sizeof(attrSet);
     }
+    if (!(lead & 2))
+    {
+        memcpy (dst, &attrUse, sizeof(attrUse));
+        dst += sizeof(attrUse);
+    }
+#endif
+    *dst++ = p->reg_type;
+    memcpy (dst, string, length);
+    dst += length;
+    *dst++ = '\0';
 
-    /* save file size of original record */
-    zebraExplain_recordBytesIncrement (zti, - recordAttr->recordSize);
-    recordAttr->recordSize = fi->file_moffset - recordOffset;
-    if (!recordAttr->recordSize)
-       recordAttr->recordSize = fi->file_max - recordOffset;
-    zebraExplain_recordBytesIncrement (zti, recordAttr->recordSize);
-
-    /* set run-number for this record */
-    recordAttr->runNumber = zebraExplain_runNumberIncrement (zti, 0);
-
-    /* update store data */
-    xfree (rec->info[recInfo_storeData]);
-    if (rGroup->flagStoreData == 1)
+    if (!diff)
     {
-        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);
-        }
+        memcpy (dst, pseqno, sizeof(*pseqno));
+        dst += sizeof(*pseqno);
     }
+    keys->buf_used = dst - keys->buf;
+    if (*pseqno)
+       (*pseqno)++;
+}
+
+static void extract_add_sort_string (RecWord *p, const char *string,
+                                    int length)
+{
+    struct sortKey *sk;
+    ZebraHandle zh = p->extractCtrl->handle;
+    struct sortKey *sortKeys = zh->sortKeys;
+
+    for (sk = sortKeys; sk; sk = sk->next)
+       if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
+           return;
+
+    sk = (struct sortKey *) xmalloc (sizeof(*sk));
+    sk->next = sortKeys;
+    sortKeys = sk;
+
+    sk->string = (char *) xmalloc (length);
+    sk->length = length;
+    memcpy (sk->string, string, length);
+
+    sk->attrSet = p->attrSet;
+    sk->attrUse = p->attrUse;
+}
+
+void extract_add_string (RecWord *p, const char *string, int length)
+{
+    assert (length > 0);
+    if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
+       extract_add_sort_string (p, string, length);
     else
+       extract_add_index_string (p, string, length);
+}
+
+static void extract_add_incomplete_field (RecWord *p)
+{
+    const char *b = p->string;
+    int remain = p->length;
+    const char **map = 0;
+
+    if (remain > 0)
+       map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+
+    while (map)
     {
-        rec->info[recInfo_storeData] = NULL;
-        rec->size[recInfo_storeData] = 0;
-    }
-    /* update database name */
-    xfree (rec->info[recInfo_databaseName]);
-    rec->info[recInfo_databaseName] =
-        rec_strdup (rGroup->databaseName, &rec->size[recInfo_databaseName]); 
+       char buf[IT_MAX_WORD+1];
+       int i, remain;
+
+       /* Skip spaces */
+       while (map && *map && **map == *CHR_SPACE)
+       {
+           remain = p->length - (b - p->string);
+           if (remain > 0)
+               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+           else
+               map = 0;
+       }
+       if (!map)
+           break;
+       i = 0;
+       while (map && *map && **map != *CHR_SPACE)
+       {
+           const char *cp = *map;
 
-    /* update offset */
-    recordAttr->recordOffset = recordOffset;
-    
-    /* commit this record */
-    rec_put (records, &rec);
-    logRecord (0);
-    return 1;
+           while (i < IT_MAX_WORD && *cp)
+               buf[i++] = *(cp++);
+           remain = p->length - (b - p->string);
+           if (remain > 0)
+               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+           else
+               map = 0;
+       }
+       if (!i)
+           return;
+       extract_add_string (p, buf, i);
+    }
+    (p->seqnos[p->reg_type])++; /* to separate this from next one  */
 }
 
-int fileExtract (SYSNO *sysno, const char *fname, 
-                 const struct recordGroup *rGroupP, int deleteFlag)
+static void extract_add_complete_field (RecWord *p)
 {
-    int r, i, fd;
-    char gprefix[128];
-    char ext[128];
-    char ext_res[128];
-    char subType[128];
-    RecType recType;
-    struct recordGroup rGroupM;
-    struct recordGroup *rGroup = &rGroupM;
-    struct file_read_info *fi;
-    void *clientData;
-
-    memcpy (rGroup, rGroupP, sizeof(*rGroupP));
-   
-    if (!rGroup->groupName || !*rGroup->groupName)
-        *gprefix = '\0';
-    else
-        sprintf (gprefix, "%s.", rGroup->groupName);
+    const char *b = p->string;
+    char buf[IT_MAX_WORD+1];
+    const char **map = 0;
+    int i = 0, remain = p->length;
 
-    logf (LOG_DEBUG, "fileExtract %s", fname);
+    if (remain > 0)
+       map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
 
-    /* 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 */
-    if (!rGroup->recordType)
-    {
-        sprintf (ext_res, "%srecordType.%s", gprefix, ext);
-        if (!(rGroup->recordType = res_get (common_resource, ext_res)))
-        {
-            sprintf (ext_res, "%srecordType", gprefix);
-            rGroup->recordType = res_get (common_resource, ext_res);
-        }
-    }
-    if (!rGroup->recordType)
-    {
-        if (records_processed < rGroup->fileVerboseLimit)
-            logf (LOG_LOG, "? %s", fname);
-        return 0;
-    }
-    if (!*rGroup->recordType)
-       return 0;
-    if (!(recType =
-         recType_byName (rGroup->recTypes, rGroup->recordType, subType,
-                         &clientData)))
+    while (remain > 0 && i < IT_MAX_WORD)
     {
-        logf (LOG_WARN, "No such record type: %s", rGroup->recordType);
-        return 0;
-    }
+       while (map && *map && **map == *CHR_SPACE)
+       {
+           remain = p->length - (b - p->string);
+           if (remain > 0)
+               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+           else
+               map = 0;
+       }
+       if (!map)
+           break;
 
-    /* determine match criteria */
-    if (!rGroup->recordId)
-    {
-        sprintf (ext_res, "%srecordId.%s", gprefix, ext);
-        rGroup->recordId = res_get (common_resource, ext_res);
+       if (i && i < IT_MAX_WORD)
+           buf[i++] = *CHR_SPACE;
+       while (map && *map && **map != *CHR_SPACE)
+       {
+           const char *cp = *map;
+
+           if (i >= IT_MAX_WORD)
+               break;
+           while (i < IT_MAX_WORD && *cp)
+               buf[i++] = *(cp++);
+           remain = p->length  - (b - p->string);
+           if (remain > 0)
+               map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
+                                       remain);
+           else
+               map = 0;
+       }
     }
+    if (!i)
+       return;
+    extract_add_string (p, buf, i);
+}
 
-    /* determine database name */
-    if (!rGroup->databaseName)
+void extract_token_add (RecWord *p)
+{
+    WRBUF wrbuf;
+    if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
+                              p->string, p->length)))
     {
-        sprintf (ext_res, "%sdatabase.%s", gprefix, ext);
-        if (!(rGroup->databaseName = res_get (common_resource, ext_res)))
-        {
-            sprintf (ext_res, "%sdatabase", gprefix);
-            rGroup->databaseName = res_get (common_resource, ext_res);
-        }
+       p->string = wrbuf_buf(wrbuf);
+       p->length = wrbuf_len(wrbuf);
     }
-    if (!rGroup->databaseName)
-        rGroup->databaseName = "Default";
+    if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
+       extract_add_complete_field (p);
+    else
+       extract_add_incomplete_field(p);
+}
 
-    /* determine if explain database */
-    
-    sprintf (ext_res, "%sexplainDatabase", gprefix);
-    rGroup->explainDatabase =
-       atoi (res_get_def (common_resource, ext_res, "0"));
+void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid)
+{
+    ZebraHandle zh = (ZebraHandle) (p->handle);
+    zebraExplain_addSchema (zh->service->zei, oid);
+}
 
-    /* announce database */
-    if (zebraExplain_curDatabase (zti, rGroup->databaseName))
+void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
+                            int cmd, struct sortKey **skp)
+{
+    struct sortKey *sk = *skp;
+    SortIdx sortIdx = zh->service->sortIdx;
+
+    sortIdx_sysno (sortIdx, sysno);
+    while (sk)
     {
-        if (zebraExplain_newDatabase (zti, rGroup->databaseName,
-                                     rGroup->explainDatabase))
-           return 0;
+       struct sortKey *sk_next = sk->next;
+       sortIdx_type (sortIdx, sk->attrUse);
+       sortIdx_add (sortIdx, sk->string, sk->length);
+       xfree (sk->string);
+       xfree (sk);
+       sk = sk_next;
     }
+    *skp = 0;
+}
 
-    if (rGroup->flagStoreData == -1)
+void encode_key_init (struct encode_info *i)
+{
+    i->sysno = 0;
+    i->seqno = 0;
+    i->cmd = -1;
+}
+
+char *encode_key_int (int d, char *bp)
+{
+    if (d <= 63)
+        *bp++ = d;
+    else if (d <= 16383)
     {
-        const char *sval;
-        sprintf (ext_res, "%sstoreData.%s", gprefix, ext);
-        if (!(sval = res_get (common_resource, ext_res)))
-        {
-            sprintf (ext_res, "%sstoreData", gprefix);
-            sval = res_get (common_resource, ext_res);
-        }
-        if (sval)
-            rGroup->flagStoreData = atoi (sval);
+        *bp++ = 64 + (d>>8);
+        *bp++ = d  & 255;
     }
-    if (rGroup->flagStoreData == -1)
-        rGroup->flagStoreData = 0;
-
-    if (rGroup->flagStoreKeys == -1)
+    else if (d <= 4194303)
     {
-        const char *sval;
-
-        sprintf (ext_res, "%sstoreKeys.%s", gprefix, ext);
-        sval = res_get (common_resource, ext_res);
-       if (!sval)
-        {
-            sprintf (ext_res, "%sstoreKeys", gprefix);
-            sval = res_get (common_resource, ext_res);
-        }
-       if (!sval)
-           sval = res_get (common_resource, "storeKeys");
-        if (sval)
-            rGroup->flagStoreKeys = atoi (sval);
+        *bp++ = 128 + (d>>16);
+        *bp++ = (d>>8) & 255;
+        *bp++ = d & 255;
     }
-    if (rGroup->flagStoreKeys == -1)
-        rGroup->flagStoreKeys = 0;
-
-    if (sysno && deleteFlag)
-        fd = -1;
     else
     {
-        if ((fd = open (fname, O_BINARY|O_RDONLY)) == -1)
-        {
-            logf (LOG_WARN|LOG_ERRNO, "open %s", fname);
-            return 0;
-        }
+        *bp++ = 192 + (d>>24);
+        *bp++ = (d>>16) & 255;
+        *bp++ = (d>>8) & 255;
+        *bp++ = d & 255;
     }
-    fi = file_read_start (fd);
-    do
-    {
-        file_begin (fi);
-        r = recordExtract (sysno, fname, rGroup, deleteFlag, fi,
-                           recType, subType, clientData);
-    } while (r && !sysno && fi->file_more);
-    file_read_stop (fi);
-    if (fd != -1)
-        close (fd);
-    return r;
+    return bp;
 }
 
-static int explain_extract (void *handle, Record rec, data1_node *n)
+void encode_key_write (char *k, struct encode_info *i, FILE *outf)
 {
-    struct recordGroup *rGroup = (struct recordGroup*) handle;
-    struct recExtractCtrl extractCtrl;
-    int i;
+    struct it_key key;
+    char *bp = i->buf;
 
-    if (zebraExplain_curDatabase (zti, rec->info[recInfo_databaseName]))
+    while ((*bp++ = *k++))
+        ;
+    memcpy (&key, k+1, sizeof(struct it_key));
+    bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
+    if (i->sysno != key.sysno)
     {
-        if (zebraExplain_newDatabase (zti, rec->info[recInfo_databaseName], 0))
-            abort ();
+        i->sysno = key.sysno;
+        i->seqno = 0;
     }
-
-    reckeys.buf_used = 0;
-    reckeys.prevAttrUse = -1;
-    reckeys.prevAttrSet = -1;
-    reckeys.prevSeqNo = 0;
-    
-    extractCtrl.init = wordInit;
-    extractCtrl.tokenAdd = addRecordKey;
-    extractCtrl.schemaAdd = addSchema;
-    extractCtrl.dh = rGroup->dh;
-    for (i = 0; i<256; i++)
-       extractCtrl.seqno[i] = 0;
-    extractCtrl.zebra_maps = rGroup->zebra_maps;
-    extractCtrl.flagShowRecords = !rGroup->flagRw;
-    
-    grs_extract_tree(&extractCtrl, n);
-
-    logf (LOG_DEBUG, "flush explain record, sysno=%d", rec->sysno);
-
-    if (rec->size[recInfo_delKeys])
+    else if (!i->seqno && !key.seqno && i->cmd == *k)
+       return;
+    bp = encode_key_int (key.seqno - i->seqno, bp);
+    i->seqno = key.seqno;
+    i->cmd = *k;
+    if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
     {
-       struct recKeys delkeys;
-
-       delkeys.buf_used = rec->size[recInfo_delKeys];
-       delkeys.buf = rec->info[recInfo_delKeys];
-       flushSortKeys (rec->sysno, 0);
-       flushRecordKeys (rec->sysno, 0, &delkeys);
+        logf (LOG_FATAL|LOG_ERRNO, "fwrite");
+        exit (1);
     }
-    flushRecordKeys (rec->sysno, 1, &reckeys);
-    flushSortKeys (rec->sysno, 1);
-
-    xfree (rec->info[recInfo_delKeys]);
-    rec->size[recInfo_delKeys] = reckeys.buf_used;
-    rec->info[recInfo_delKeys] = reckeys.buf;
-    reckeys.buf = NULL;
-    reckeys.buf_max = 0;
-
-    return 0;
 }
+
index aba2cbc..6064462 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 1995-0000, Index Data
+ * Copyright (C) 1995-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss, Heikki Levanto
- * (log at the end)
+ * $Id: index.h,v 1.73 2002-02-20 17:30:01 adam Exp $
  */
 
 #ifndef INDEX_H
@@ -25,6 +25,7 @@
 #endif
 #include <yaz/data1.h>
 #include <recctrl.h>
+#include "zebraapi.h"
 
 YAZ_BEGIN_CDECL
 
@@ -68,13 +69,6 @@ struct recordGroup {
     int          fileVerboseLimit;
     int          databaseNamePath;
     int          explainDatabase;
-#if ZEBRASDR
-    int          useSDR;
-#endif
-    data1_handle dh;
-    BFiles       bfs;
-    ZebraMaps    zebra_maps;
-    RecTypes     recTypes;
 };
 
 void getFnameTmp (Res res, char *fname, int no);
@@ -93,21 +87,21 @@ struct dir_entry *dir_open (const char *rep);
 void dir_sort (struct dir_entry *e);
 void dir_free (struct dir_entry **e_p);
 
-void repositoryUpdate (struct recordGroup *rGroup);
-void repositoryAdd (struct recordGroup *rGroup);
-void repositoryDelete (struct recordGroup *rGroup);
-void repositoryShow (struct recordGroup *rGroup);
+void repositoryUpdate (ZebraHandle zh);
+void repositoryAdd (ZebraHandle zh);
+void repositoryDelete (ZebraHandle zh);
+void repositoryShow (ZebraHandle zh);
 
-int key_open (struct recordGroup *rGroup, int mem);
-int key_close (struct recordGroup *group);
+int key_open (ZebraHandle zh, int mem);
+int key_close (ZebraHandle zh);
 int key_compare (const void *p1, const void *p2);
 int key_get_pos (const void *p);
 int key_compare_it (const void *p1, const void *p2);
 int key_qsort_compare (const void *p1, const void *p2);
 void key_logdump (int mask, const void *p);
-void inv_prstat (BFiles bfs);
+void inv_prstat (ZebraHandle zh);
 void inv_compact (BFiles bfs);
-void key_input (BFiles bfs, int nkeys, int cache, Res res);
+void key_input (ZebraHandle zh, int nkeys, int cache, Res res);
 ISAMS_M key_isams_m (Res res, ISAMS_M me);
 #if ZMBOL
 ISAMC_M key_isamc_m (Res res, ISAMC_M me);
@@ -136,13 +130,13 @@ int index_char_cvt (int c);
 int index_word_prefix (char *string, int attset_ordinal,
                        int local_attribute, const char *databaseName);
 
-int fileExtract (SYSNO *sysno, const char *fname,
+int fileExtract (ZebraHandle zh, SYSNO *sysno, const char *fname,
                  const struct recordGroup *rGroup, int deleteFlag);
 
-void zebraIndexLockMsg (const char *str);
-void zebraIndexUnlock (void);
-int zebraIndexLock (BFiles bfs, int commitNow, const char *rval);
-int zebraIndexWait (int commitPhase);
+void zebraIndexLockMsg (ZebraHandle zh, const char *str);
+void zebraIndexUnlock (ZebraHandle zh);
+int zebraIndexLock (BFiles bfs, ZebraHandle zh, int commitNow, const char *rval);
+int zebraIndexWait (ZebraHandle zh, int commitPhase);
 
 #define FNAME_MAIN_LOCK   "zebraidx.LCK"
 #define FNAME_COMMIT_LOCK "zebracmt.LCK"
@@ -158,266 +152,28 @@ int zebra_unlock (ZebraLockHandle h);
 int zebra_lock_fd (ZebraLockHandle h);
 void zebra_lock_prefix (Res res, char *dst);
 
+int zebra_lock_w (ZebraLockHandle h);
+int zebra_lock_r (ZebraLockHandle h);
+
 void zebra_load_atts (data1_handle dh, Res res);
 
 int key_SU_decode (int *ch, const unsigned char *out);
 int key_SU_encode (int ch, char *out);
 
-extern Res common_resource;
+// extern Res common_resource;
+
+struct encode_info {
+    int  sysno;
+    int  seqno;
+    int  cmd;
+    char buf[768];
+};
+
+void encode_key_init (struct encode_info *i);
+char *encode_key_int (int d, char *bp);
+void encode_key_write (char *k, struct encode_info *i, FILE *outf);
+
 
 YAZ_END_CDECL
 
 #endif
-/*
- * $Log: index.h,v $
- * Revision 1.72  2001-11-19 23:08:29  adam
- * Added const qualifier for name parameter of key_SU_decode.
- *
- * Revision 1.71  2001/11/19 23:05:22  adam
- * Added a few prototypes.
- *
- * Revision 1.70  2000/12/05 10:01:44  adam
- * Fixed bug regarding user-defined attribute sets.
- *
- * Revision 1.69  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.68  2000/02/24 11:00:07  adam
- * Fixed bug: indexer would run forever when lock dir was non-existant.
- *
- * Revision 1.67  1999/11/30 13:48:03  adam
- * Improved installation. Updated for inclusion of YAZ header files.
- *
- * Revision 1.66  1999/07/14 13:21:34  heikki
- * Added isam-d files. Compiles (almost) clean. Doesn't work at all
- *
- * Revision 1.65  1999/07/14 10:59:26  adam
- * Changed functions isc_getmethod, isams_getmethod.
- * Improved fatal error handling (such as missing EXPLAIN schema).
- *
- * Revision 1.64  1999/06/30 15:07:23  heikki
- * Adding isamh stuff
- *
- * Revision 1.63  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.62  1999/05/12 13:08:06  adam
- * First version of ISAMS.
- *
- * Revision 1.61  1999/03/09 16:27:49  adam
- * More work on SDRKit integration.
- *
- * Revision 1.60  1998/10/16 08:14:31  adam
- * Updated record control system.
- *
- * Revision 1.59  1998/06/08 14:43:11  adam
- * Added suport for EXPLAIN Proxy servers - added settings databasePath
- * and explainDatabase to facilitate this. Increased maximum number
- * of databases and attributes in one register.
- *
- * Revision 1.58  1998/05/20 10:12:16  adam
- * Implemented automatic EXPLAIN database maintenance.
- * Modified Zebra to work with ASN.1 compiled version of YAZ.
- *
- * Revision 1.57  1998/03/05 08:45:12  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.56  1998/01/12 15:04:08  adam
- * The test option (-s) only uses read-lock (and not write lock).
- *
- * Revision 1.55  1997/10/27 14:33:04  adam
- * Moved towards generic character mapping depending on "structure"
- * field in abstract syntax file. Fixed a few memory leaks. Fixed
- * bug with negative integers when doing searches with relational
- * operators.
- *
- * Revision 1.54  1997/09/29 09:08:36  adam
- * Revised locking system to be thread safe for the server.
- *
- * Revision 1.53  1997/09/25 14:54:43  adam
- * WIN32 files lock support.
- *
- * Revision 1.52  1997/09/22 12:39:06  adam
- * Added get_pos method for the ranked result sets.
- *
- * Revision 1.51  1997/09/18 08:59:19  adam
- * Extra generic handle for the character mapping routines.
- *
- * Revision 1.50  1997/09/17 12:19:13  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.49  1997/09/05 15:30:08  adam
- * Changed prototype for chr_map_input - added const.
- * Added support for C++, headers uses extern "C" for public definitions.
- *
- * Revision 1.48  1997/02/12 20:39:45  adam
- * Implemented options -f <n> that limits the log to the first <n>
- * records.
- * Changed some log messages also.
- *
- * Revision 1.47  1996/12/23 15:30:44  adam
- * Work on truncation.
- * Bug fix: result sets weren't deleted after server shut down.
- *
- * Revision 1.46  1996/11/08 11:10:19  adam
- * Buffers used during file match got bigger.
- * Compressed ISAM support everywhere.
- * Bug fixes regarding masking characters in queries.
- * Redesigned Regexp-2 queries.
- *
- * Revision 1.45  1996/10/29 14:09:42  adam
- * Use of cisam system - enabled if setting isamc is 1.
- *
- * Revision 1.44  1996/06/06 12:08:40  quinn
- * Added showRecord function
- *
- * Revision 1.43  1996/06/04  10:18:12  adam
- * Search/scan uses character mapping module.
- *
- * Revision 1.42  1996/06/04  08:20:16  quinn
- * Smallish
- *
- * Revision 1.41  1996/06/04  07:54:55  quinn
- * Added output-map.
- *
- * Revision 1.40  1996/05/31  09:06:58  quinn
- * Work on character-set handling
- *
- * Revision 1.39  1996/05/14  14:04:33  adam
- * In zebraidx, the 'stat' command is improved. Statistics about ISAM/DICT
- * is collected.
- *
- * Revision 1.38  1996/04/12  07:02:23  adam
- * File update of single files.
- *
- * Revision 1.37  1996/03/26 16:01:13  adam
- * New setting lockPath: directory of various lock files.
- *
- * Revision 1.36  1996/03/21  14:50:09  adam
- * File update uses modify-time instead of change-time.
- *
- * Revision 1.35  1996/02/12  18:45:36  adam
- * New fileVerboseFlag in record group control.
- *
- * Revision 1.34  1995/12/11  11:43:29  adam
- * Locking based on fcntl instead of flock.
- * Setting commitEnable removed. Command line option -n can be used to
- * prevent commit if commit setting is defined in the configuration file.
- *
- * Revision 1.33  1995/12/08  16:22:53  adam
- * Work on update while servers are running. Three lock files introduced.
- * The servers reload their registers when necessary, but they don't
- * reestablish result sets yet.
- *
- * Revision 1.32  1995/12/07  17:38:46  adam
- * Work locking mechanisms for concurrent updates/commit.
- *
- * Revision 1.31  1995/12/06  12:41:22  adam
- * New command 'stat' for the index program.
- * Filenames can be read from stdin by specifying '-'.
- * Bug fix/enhancement of the transformation from terms to regular
- * expressons in the search engine.
- *
- * Revision 1.30  1995/12/05  11:25:02  adam
- * Include of zebraver.h.
- *
- * Revision 1.29  1995/11/28  09:09:40  adam
- * Zebra config renamed.
- * Use setting 'recordId' to identify record now.
- * Bug fix in recindex.c: rec_release_blocks was invokeded even
- * though the blocks were already released.
- * File traversal properly deletes records when needed.
- *
- * Revision 1.28  1995/11/27  13:58:53  adam
- * New option -t. storeStore data implemented in server.
- *
- * Revision 1.27  1995/11/25  10:24:06  adam
- * More record fields - they are enumerated now.
- * New options: flagStoreData flagStoreKey.
- *
- * Revision 1.26  1995/11/22  17:19:17  adam
- * Record management uses the bfile system.
- *
- * Revision 1.25  1995/11/21  15:29:12  adam
- * Config file 'base' read by default by both indexer and server.
- *
- * Revision 1.24  1995/11/21  15:01:15  adam
- * New general match criteria implemented.
- * New feature: document groups.
- *
- * Revision 1.23  1995/11/20  16:59:45  adam
- * New update method: the 'old' keys are saved for each records.
- *
- * Revision 1.22  1995/11/20  11:56:26  adam
- * Work on new traversal.
- *
- * Revision 1.21  1995/11/16  15:34:55  adam
- * Uses new record management system in both indexer and server.
- *
- * Revision 1.20  1995/11/15  14:46:18  adam
- * Started work on better record management system.
- *
- * Revision 1.19  1995/10/27  14:00:11  adam
- * Implemented detection of database availability.
- *
- * Revision 1.18  1995/10/17  18:02:08  adam
- * New feature: databases. Implemented as prefix to words in dictionary.
- *
- * Revision 1.17  1995/10/13  16:01:49  adam
- * Work on relations.
- *
- * Revision 1.16  1995/10/10  12:24:38  adam
- * Temporary sort files are compressed.
- *
- * Revision 1.15  1995/10/04  16:57:19  adam
- * Key input and merge sort in one pass.
- *
- * Revision 1.14  1995/09/29  14:01:40  adam
- * Bug fixes.
- *
- * Revision 1.13  1995/09/28  14:22:56  adam
- * Sort uses smaller temporary files.
- *
- * Revision 1.12  1995/09/28  12:10:32  adam
- * Bug fixes. Field prefix used in queries.
- *
- * Revision 1.11  1995/09/27  12:22:28  adam
- * More work on extract in record control.
- * Field name is not in isam keys but in prefix in dictionary words.
- *
- * Revision 1.10  1995/09/14  07:48:23  adam
- * Record control management.
- *
- * Revision 1.9  1995/09/11  13:09:33  adam
- * More work on relevance feedback.
- *
- * Revision 1.8  1995/09/08  14:52:27  adam
- * Minor changes. Dictionary is lower case now.
- *
- * Revision 1.7  1995/09/06  16:11:16  adam
- * Option: only one word key per file.
- *
- * Revision 1.6  1995/09/05  15:28:39  adam
- * More work on search engine.
- *
- * Revision 1.5  1995/09/04  12:33:42  adam
- * Various cleanup. YAZ util used instead.
- *
- * Revision 1.4  1995/09/04  09:10:35  adam
- * More work on index add/del/update.
- * Merge sort implemented.
- * Initial work on z39 server.
- *
- * Revision 1.3  1995/09/01  14:06:35  adam
- * Split of work into more files.
- *
- * Revision 1.2  1995/09/01  10:30:24  adam
- * More work on indexing. Not working yet.
- *
- * Revision 1.1  1995/08/31  14:50:24  adam
- * New simple file index tool.
- *
- */
index ce82cd6..5a23007 100644 (file)
@@ -14,6 +14,7 @@
 #if ZMBOL
 #include "../isamc/isamd-p.h"
 #endif
+#include "zserver.h"
 
 struct inv_stat_info {
     ISAMS isams;
@@ -128,8 +129,9 @@ static int inv_stat_handle (char *name, const char *info, int pos,
     return 0;
 }
 
-void inv_prstat (BFiles bfs)
+void inv_prstat (ZebraHandle zh)
 {
+    BFiles bfs = zh->service->bfs;
     Dict dict;
     ISAMS isams = NULL;
 #if ZMBOL
@@ -156,11 +158,11 @@ void inv_prstat (BFiles bfs)
         logf (LOG_FATAL, "dict_open fail");
         exit (1);
     }
-    if (res_get_match (common_resource, "isam", "s", ISAM_DEFAULT))
+    if (res_get_match (zh->service->res, "isam", "s", ISAM_DEFAULT))
     {
        struct ISAMS_M_s isams_m;
         isams = isams_open (bfs, FNAME_ISAMS, 0,
-                           key_isams_m(common_resource, &isams_m));
+                           key_isams_m(zh->service->res, &isams_m));
         if (!isams)
         {
             logf (LOG_FATAL, "isams_open fail");
@@ -168,32 +170,32 @@ void inv_prstat (BFiles bfs)
         }
     }
 #if ZMBOL
-    else if (res_get_match (common_resource, "isam", "i", ISAM_DEFAULT))
+    else if (res_get_match (zh->service->res, "isam", "i", ISAM_DEFAULT))
     {
         isam = is_open (bfs, FNAME_ISAM, key_compare, 0,
-                       sizeof(struct it_key), common_resource);
+                       sizeof(struct it_key), zh->service->res);
         if (!isam)
         {
             logf (LOG_FATAL, "is_open fail");
             exit (1);
         }
     }
-    else if (res_get_match (common_resource, "isam", "d", ISAM_DEFAULT))
+    else if (res_get_match (zh->service->res, "isam", "d", ISAM_DEFAULT))
     {
        struct ISAMD_M_s isamd_m;
         isamd = isamd_open (bfs, FNAME_ISAMD, 0, 
-                            key_isamd_m(common_resource,&isamd_m));
+                            key_isamd_m(zh->service->res,&isamd_m));
         if (!isamd)
         {
             logf (LOG_FATAL, "isamd_open fail");
             exit (1);
         }
     }
-    else if (res_get_match (common_resource, "isam", "c", ISAM_DEFAULT))
+    else if (res_get_match (zh->service->res, "isam", "c", ISAM_DEFAULT))
     {
        struct ISAMC_M_s isamc_m;
         isamc = isc_open (bfs, FNAME_ISAMC, 0,
-                         key_isamc_m (common_resource, &isamc_m));
+                         key_isamc_m (zh->service->res, &isamc_m));
         if (!isamc)
         {
             logf (LOG_FATAL, "isc_open fail");
@@ -323,7 +325,10 @@ void inv_prstat (BFiles bfs)
 /*
  *
  * $Log: invstat.c,v $
- * Revision 1.21  2000-07-13 10:14:20  heikki
+ * Revision 1.22  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.21  2000/07/13 10:14:20  heikki
  * Removed compiler warnings when making zebra
  *
  * Revision 1.20  1999/12/01 13:30:30  adam
index 92e64ec..b9d7f06 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * Copyright (C) 1994-2000, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss, Heikki Levanto
  *
- * (log at the end)
+ * $Id: kinput.c,v 1.45 2002-02-20 17:30:01 adam Exp $
  *
  * Bugs
  *  - Allocates a lot of memory for the merge process, but never releases it.
@@ -412,6 +412,7 @@ int heap_inpc (struct heap_info *hi)
         }
     }
     xfree (isamc_i);
+    xfree (hci.key);
     return 0;
 } 
 
@@ -672,7 +673,7 @@ void zebra_index_merge (ZebraHandle zh)
        
     for (i = 1; i<=nkeys; i++)
     {
-       extract_get_fname_tmp  (zh, rbuf, i);
+        extract_get_fname_tmp  (zh, rbuf, i);
         unlink (rbuf);
     }
     logf (LOG_LOG, "Iterations . . .%7d", no_iterations);
@@ -683,16 +684,9 @@ void zebra_index_merge (ZebraHandle zh)
     zh->key_file_no = 0;
 }
 
-void key_input (BFiles bfs, int nkeys, int cache, Res res)
+void key_input (ZebraHandle zh, int nkeys, int cache, Res res)
                 
 {
-    Dict dict;
-    ISAMS isams = NULL;
-#if ZMBOL
-    ISAM isam = NULL;
-    ISAMC isamc = NULL;
-    ISAMD isamd = NULL;
-#endif
     struct key_file **kf;
     char rbuf[1024];
     int i, r;
@@ -713,58 +707,6 @@ void key_input (BFiles bfs, int nkeys, int cache, Res res)
         if (!nkeys)
             return ;
     }
-    dict = dict_open (bfs, FNAME_DICT, cache, 1, 0);
-    if (!dict)
-    {
-        logf (LOG_FATAL, "dict_open fail");
-        exit (1);
-    }
-    if (res_get_match (res, "isam", "s", ISAM_DEFAULT))
-    {
-       struct ISAMS_M_s isams_m;
-        isams = isams_open (bfs, FNAME_ISAMS, 1,
-                           key_isams_m (res, &isams_m));
-        if (!isams)
-        {
-            logf (LOG_FATAL, "isams_open fail");
-            exit (1);
-        }
-       logf (LOG_LOG, "isams opened");
-    }
-#if ZMBOL
-    else if (res_get_match (res, "isam", "i", ISAM_DEFAULT))
-    {
-        isam = is_open (bfs, FNAME_ISAM, key_compare, 1,
-                       sizeof(struct it_key), res);
-        if (!isam)
-        {
-            logf (LOG_FATAL, "is_open fail");
-            exit (1);
-        }
-    }
-    else if (res_get_match (res, "isam", "d", ISAM_DEFAULT))
-    {
-       struct ISAMD_M_s isamd_m;
-        isamd = isamd_open (bfs, FNAME_ISAMD, 1,
-                         key_isamd_m (res,&isamd_m));
-        if (!isamd)
-        {
-            logf (LOG_FATAL, "isamd_open fail");
-            exit (1);
-        }
-    }
-    else if (res_get_match (res, "isam", "c", ISAM_DEFAULT))
-    {
-       struct ISAMC_M_s isamc_m;
-        isamc = isc_open (bfs, FNAME_ISAMC, 1,
-                         key_isamc_m (res, &isamc_m));
-        if (!isamc)
-        {
-            logf (LOG_FATAL, "isc_open fail");
-            exit (1);
-        }
-    }
-#endif
     kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
     progressInfo.totalBytes = 0;
     progressInfo.totalOffset = 0;
@@ -779,40 +721,28 @@ void key_input (BFiles bfs, int nkeys, int cache, Res res)
         progressInfo.totalOffset += kf[i]->buf_size;
     }
     hi = key_heap_init (nkeys, key_qsort_compare);
-    hi->dict = dict;
-    hi->isams = isams;
+    hi->dict = zh->service->dict;
+    hi->isams = zh->service->isams;
 #if ZMBOL
-    hi->isam = isam;
-    hi->isamc = isamc;
-    hi->isamd = isamd;
+    hi->isam = zh->service->isam;
+    hi->isamc = zh->service->isamc;
+    hi->isamd = zh->service->isamd;
 #endif
     
     for (i = 1; i<=nkeys; i++)
         if ((r = key_file_read (kf[i], rbuf)))
             key_heap_insert (hi, rbuf, r, kf[i]);
-    if (isams)
+    if (hi->isams)
        heap_inps (hi);
 #if ZMBOL
-    else if (isamc)
+    else if (hi->isamc)
         heap_inpc (hi);
-    else if (isam)
+    else if (hi->isam)
        heap_inp (hi);
-    else if (isamd)
+    else if (hi->isamd)
        heap_inpd (hi);
 #endif
        
-    dict_close (dict);
-    if (isams)
-       isams_close (isams);
-#if ZMBOL
-    if (isam)
-        is_close (isam);
-    if (isamc)
-        isc_close (isamc);
-    if (isamd)
-        isamd_close (isamd);
-#endif
-   
     for (i = 1; i<=nkeys; i++)
     {
         getFnameTmp (res, rbuf, i);
@@ -827,157 +757,3 @@ void key_input (BFiles bfs, int nkeys, int cache, Res res)
     /* xmalloc_trav("unfreed"); while hunting leaks */     
 }
 
-
-
-/*
- * $Log: kinput.c,v $
- * Revision 1.44  2000-05-18 12:01:36  adam
- * System call times(2) used again. More 64-bit fixes.
- *
- * Revision 1.43  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.42  1999/12/01 21:58:48  adam
- * Proper handle of illegal use of isams.
- *
- * Revision 1.41  1999/11/30 13:48:03  adam
- * Improved installation. Updated for inclusion of YAZ header files.
- *
- * Revision 1.40  1999/09/08 12:12:39  adam
- * Removed log message.
- *
- * Revision 1.39  1999/08/18 10:39:20  heikki
- * Added a comment on memory leaks
- *
- * Revision 1.38  1999/08/18 08:38:04  heikki
- * Memory leak hunting
- *
- * Revision 1.37  1999/07/14 13:21:34  heikki
- * Added isam-d files. Compiles (almost) clean. Doesn't work at all
- *
- * Revision 1.36  1999/07/14 10:59:26  adam
- * Changed functions isc_getmethod, isams_getmethod.
- * Improved fatal error handling (such as missing EXPLAIN schema).
- *
- * Revision 1.35  1999/06/30 15:07:23  heikki
- * Adding isamh stuff
- *
- * Revision 1.34  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.33  1999/05/15 14:36:38  adam
- * Updated dictionary. Implemented "compression" of dictionary.
- *
- * Revision 1.32  1999/05/12 13:08:06  adam
- * First version of ISAMS.
- *
- * Revision 1.31  1999/02/02 14:50:56  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.30  1998/10/28 10:53:57  adam
- * Added type cast to prevent warning.
- *
- * Revision 1.29  1998/06/11 15:41:39  adam
- * Minor changes.
- *
- * Revision 1.28  1998/03/05 08:45:12  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.27  1998/02/17 10:32:52  adam
- * Fixed bug: binary files weren't opened with flag b on NT.
- *
- * Revision 1.26  1998/01/29 13:39:13  adam
- * Compress ISAM is default.
- *
- * Revision 1.25  1997/09/17 12:19:14  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.24  1997/09/09 13:38:07  adam
- * Partial port to WIN95/NT.
- *
- * Revision 1.23  1997/09/04 13:57:39  adam
- * Added O_BINARY for open calls.
- *
- * Revision 1.22  1997/02/12 20:39:45  adam
- * Implemented options -f <n> that limits the log to the first <n>
- * records.
- * Changed some log messages also.
- *
- * Revision 1.21  1996/11/08 11:10:23  adam
- * Buffers used during file match got bigger.
- * Compressed ISAM support everywhere.
- * Bug fixes regarding masking characters in queries.
- * Redesigned Regexp-2 queries.
- *
- * Revision 1.20  1996/11/01 08:58:41  adam
- * Interface to isamc system now includes update and delete.
- *
- * Revision 1.19  1996/10/29 14:09:46  adam
- * Use of cisam system - enabled if setting isamc is 1.
- *
- * Revision 1.18  1996/06/04 10:18:59  adam
- * Minor changes - removed include of ctype.h.
- *
- * Revision 1.17  1996/05/14  15:47:07  adam
- * Cleanup of various buffer size entities.
- *
- * Revision 1.16  1996/04/09  10:05:20  adam
- * Bug fix: prev_name buffer possibly too small; allocated in key_file_init.
- *
- * Revision 1.15  1996/03/21  14:50:09  adam
- * File update uses modify-time instead of change-time.
- *
- * Revision 1.14  1996/02/07  14:06:37  adam
- * Better progress report during register merge.
- * New command: clean - removes temporary shadow files.
- *
- * Revision 1.13  1996/02/05  12:30:00  adam
- * Logging reduced a bit.
- * The remaining running time is estimated during register merge.
- *
- * Revision 1.12  1995/12/06  17:49:19  adam
- * Uses dict_delete now.
- *
- * Revision 1.11  1995/12/06  16:06:43  adam
- * Better diagnostics. Work on 'real' dictionary deletion.
- *
- * Revision 1.10  1995/12/06  12:41:22  adam
- * New command 'stat' for the index program.
- * Filenames can be read from stdin by specifying '-'.
- * Bug fix/enhancement of the transformation from terms to regular
- * expressons in the search engine.
- *
- * Revision 1.9  1995/10/10  12:24:39  adam
- * Temporary sort files are compressed.
- *
- * Revision 1.8  1995/10/04  16:57:19  adam
- * Key input and merge sort in one pass.
- *
- * Revision 1.7  1995/10/02  15:18:52  adam
- * New member in recRetrieveCtrl: diagnostic.
- *
- * Revision 1.6  1995/09/29  15:51:56  adam
- * First work on multi-way read.
- *
- * Revision 1.5  1995/09/29  14:01:43  adam
- * Bug fixes.
- *
- * Revision 1.4  1995/09/28  14:22:57  adam
- * Sort uses smaller temporary files.
- *
- * Revision 1.3  1995/09/06  16:11:17  adam
- * Option: only one word key per file.
- *
- * Revision 1.2  1995/09/04  12:33:42  adam
- * Various cleanup. YAZ util used instead.
- *
- * Revision 1.1  1995/09/04  09:10:37  adam
- * More work on index add/del/update.
- * Merge sort implemented.
- * Initial work on z39 server.
- *
- */
-
index 26af684..4904de4 100644 (file)
@@ -4,7 +4,10 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: lockidx.c,v $
- * Revision 1.20  2000-10-16 20:16:00  adam
+ * Revision 1.21  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.20  2000/10/16 20:16:00  adam
  * Fixed problem with close of lock file for WIN32.
  *
  * Revision 1.19  2000/09/05 14:04:05  adam
 #include <errno.h>
 
 #include "index.h"
+#include "zserver.h"
 
 static ZebraLockHandle server_lock_main = NULL;
 static ZebraLockHandle server_lock_cmt = NULL;
 static ZebraLockHandle server_lock_org = NULL;
 
-int zebraIndexWait (int commitPhase)
+int zebraIndexWait (ZebraHandle zh, int commitPhase)
 {
     ZebraLockHandle h;
 
@@ -101,7 +105,7 @@ int zebraIndexWait (int commitPhase)
     {
        char path[1024];
 
-       zebra_lock_prefix (common_resource, path);
+       zebra_lock_prefix (zh->service->res, path);
        strcat (path, FNAME_COMMIT_LOCK);
        server_lock_cmt = zebra_lock_create (path, 1);
        if (!server_lock_cmt)
@@ -116,7 +120,7 @@ int zebraIndexWait (int commitPhase)
     {
        char path[1024];
 
-       zebra_lock_prefix (common_resource, path);
+       zebra_lock_prefix (zh->service->res, path);
        strcat (path, FNAME_ORG_LOCK);
        server_lock_org = zebra_lock_create (path, 1);
        if (!server_lock_org)
@@ -153,7 +157,7 @@ int zebraIndexWait (int commitPhase)
 }
 
 
-void zebraIndexLockMsg (const char *str)
+void zebraIndexLockMsg (ZebraHandle zh, const char *str)
 {
     char path[1024];
     int l, r, fd;
@@ -168,17 +172,17 @@ void zebraIndexLockMsg (const char *str)
         logf (LOG_FATAL|LOG_ERRNO, "write lock file");
         exit (1);
     }
-    zebra_lock_prefix (common_resource, path);
+    zebra_lock_prefix (zh->service->res, path);
     strcat (path, FNAME_TOUCH_TIME);
     fd = creat (path, 0666);
     close (fd);
 }
 
-void zebraIndexUnlock (void)
+void zebraIndexUnlock (ZebraHandle zh)
 {
     char path[1024];
     
-    zebra_lock_prefix (common_resource, path);
+    zebra_lock_prefix (zh->service->res, path);
     strcat (path, FNAME_MAIN_LOCK);
 #ifdef WIN32
     zebra_lock_destroy (server_lock_main);
@@ -192,7 +196,8 @@ void zebraIndexUnlock (void)
     server_lock_main = 0;
 }
 
-int zebraIndexLock (BFiles bfs, int commitNow, const char *rval)
+int zebraIndexLock (BFiles bfs, ZebraHandle zh, int commitNow,
+                    const char *rval)
 {
     char path[1024];
     char buf[256];
@@ -201,7 +206,7 @@ int zebraIndexLock (BFiles bfs, int commitNow, const char *rval)
     if (server_lock_main)
         return 0;
 
-    zebra_lock_prefix (common_resource, path);
+    zebra_lock_prefix (zh->service->res, path);
     strcat (path, FNAME_MAIN_LOCK);
     while (1)
     {
index 123f7e6..325ac4a 100644 (file)
@@ -1,50 +1,9 @@
 /*
- * Copyright (C) 1994-1999, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Log: lockutil.c,v $
- * Revision 1.12  1999-05-26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.11  1999/02/02 14:50:59  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.10  1997/09/29 09:08:36  adam
- * Revised locking system to be thread safe for the server.
- *
- * Revision 1.9  1997/09/25 14:54:43  adam
- * WIN32 files lock support.
- *
- * Revision 1.8  1997/09/17 12:19:15  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.7  1997/09/09 13:38:08  adam
- * Partial port to WIN95/NT.
- *
- * Revision 1.6  1996/10/29 14:08:14  adam
- * Uses resource lockDir instead of lockPath.
- *
- * Revision 1.5  1996/03/26 16:01:13  adam
- * New setting lockPath: directory of various lock files.
- *
- * Revision 1.4  1995/12/13  08:46:10  adam
- * Locking uses F_WRLCK and F_RDLCK again!
- *
- * Revision 1.3  1995/12/12  16:00:57  adam
- * System call sync(2) used after update/commit.
- * Locking (based on fcntl) uses F_EXLCK and F_SHLCK instead of F_WRLCK
- * and F_RDLCK.
- *
- * Revision 1.2  1995/12/11  11:43:29  adam
- * Locking based on fcntl instead of flock.
- * Setting commitEnable removed. Command line option -n can be used to
- * prevent commit if commit setting is defined in the configuration file.
- *
- * Revision 1.1  1995/12/07  17:38:47  adam
- * Work locking mechanisms for concurrent updates/commit.
- *
+ * $Id: lockutil.c,v 1.13 2002-02-20 17:30:01 adam Exp $
  */
 #include <stdio.h>
 #include <assert.h>
@@ -120,6 +79,24 @@ static int unixLock (int fd, int type, int cmd)
 }
 #endif
 
+int zebra_lock_w (ZebraLockHandle h)
+{
+#ifdef WIN32
+    return _locking (h->fd, _LK_LOCK, 1);
+#else
+    return unixLock (h->fd, F_WRLCK, F_SETLKW);
+#endif
+}
+
+int zebra_lock_r (ZebraLockHandle h)
+{
+#ifdef WIN32
+    return _locking (h->fd, _LK_LOCK, 1);
+#else
+    return unixLock (h->fd, F_RDLCK, F_SETLKW);
+#endif
+}
+
 int zebra_lock (ZebraLockHandle h)
 {
 #ifdef WIN32
index 60310e4..3508f2a 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 1994-2001, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  *
- * $Id: main.c,v 1.81 2001-11-19 23:29:09 adam Exp $
+ * $Id: main.c,v 1.82 2002-02-20 17:30:01 adam Exp $
  */
 #include <stdio.h>
 #include <string.h>
 #endif
 
 #include <yaz/data1.h>
+#include "zebraapi.h"
+#include "zserver.h"
 #include "index.h"
 #include "recindex.h"
 
-#ifndef ZEBRASDR
-#define ZEBRASDR 0
-#endif
-
-#if ZEBRASDR
-#include "zebrasdr.h"
-#endif
-
 char *prog;
 
-Res common_resource = 0;
-
-
 int main (int argc, char **argv)
 {
     int ret;
     int cmd = 0;
     char *arg;
-    char *configName = FNAME_CONFIG;
+    char *configName = 0;
     int nsections = 0;
     int disableCommit = 0;
     size_t mem_max = 0;
@@ -43,6 +34,8 @@ int main (int argc, char **argv)
     char nbuf[100];
 #endif
     struct recordGroup rGroupDef;
+    ZebraService zs = 0;
+    ZebraHandle zh = 0;
 
     nmem_init ();
 
@@ -52,10 +45,6 @@ int main (int argc, char **argv)
     yaz_log_init_prefix (nbuf);
 #endif
 
-#if ZEBRASDR
-    zebraSdr_std ();
-    rGroupDef.useSDR = 0;
-#endif
     rGroupDef.groupName = NULL;
     rGroupDef.databaseName = NULL;
     rGroupDef.path = NULL;
@@ -67,10 +56,6 @@ int main (int argc, char **argv)
     rGroupDef.databaseNamePath = 0;
     rGroupDef.explainDatabase = 0;
     rGroupDef.fileVerboseLimit = 100000;
-    rGroupDef.zebra_maps = NULL;
-    rGroupDef.dh = data1_create ();
-    rGroupDef.recTypes = recTypes_init (rGroupDef.dh);
-    recTypes_default_handlers (rGroupDef.recTypes);
 
     prog = *argv;
     if (argc < 2)
@@ -93,25 +78,18 @@ int main (int argc, char **argv)
        " -v <level>    Set logging to <level>.\n"
         " -l <file>     Write log to <file>.\n"
         " -f <n>        Display information for the first <n> records.\n"
-#if ZEBRASDR
-       " -S            Use SDRKit\n"
-#endif
         " -V            Show version.\n", *argv
                  );
         exit (1);
     }
     while ((ret = options ("sVt:c:g:d:m:v:nf:l:"
-#if ZEBRASDR
-                          "S"
-#endif
                           , argv, argc, &arg)) != -2)
     {
         if (ret == 0)
         {
-            const char *rval;
             if(cmd == 0) /* command */
             {
-                if (!common_resource)
+                if (!zs)
                 {
 #if ZMBOL
                     logf (LOG_LOG, "zmbol version %s %s",
@@ -120,27 +98,9 @@ int main (int argc, char **argv)
                     logf (LOG_LOG, "zebra version %s %s",
                           ZEBRAVER, ZEBRADATE);
 #endif
-                    common_resource = res_open (configName ?
-                                                configName : FNAME_CONFIG);
-                    if (!common_resource)
-                    {
-                        logf (LOG_FATAL, "cannot read file `%s'", configName);
-                        exit (1);
-                    }
-                    data1_set_tabpath (rGroupDef.dh, res_get (common_resource,
-                                                             "profilePath"));
-
-                   rGroupDef.bfs =
-                       bfs_create (res_get (common_resource, "register"));
-                    if (!rGroupDef.bfs)
-                    {
-                        logf (LOG_FATAL, "Cannot access register");
-                        exit(1);
-                    }
+                    zs = zebra_start (configName ? configName : FNAME_CONFIG);
 
-                    bf_lockDir (rGroupDef.bfs,
-                               res_get (common_resource, "lockDir"));
-                   rGroupDef.zebra_maps = zebra_maps_open (common_resource);
+                    zh = zebra_open (zs);
                 }
                 if (!strcmp (arg, "update"))
                     cmd = 'u';
@@ -154,83 +114,23 @@ int main (int argc, char **argv)
                     cmd = 'd';
                else if (!strcmp (arg, "init"))
                {
-                   zebraIndexUnlock(); 
-                   rval = res_get (common_resource, "shadow");
-                   zebraIndexLock (rGroupDef.bfs, 0, rval);
-                   if (rval && *rval)
-                       bf_cache (rGroupDef.bfs, rval);
-                   zebraIndexLockMsg ("w");
-                   bf_reset (rGroupDef.bfs);
+                    zebra_init (zh);
                }
                 else if (!strcmp (arg, "commit"))
                 {
-                    rval = res_get (common_resource, "shadow");
-                    zebraIndexLock (rGroupDef.bfs, 1, rval);
-                    if (rval && *rval)
-                        bf_cache (rGroupDef.bfs, rval);
-                    else
-                    {
-                        logf (LOG_FATAL, "Cannot perform commit");
-                        logf (LOG_FATAL, "No shadow area defined");
-                        exit (1);
-                    }
-                    if (bf_commitExists (rGroupDef.bfs))
-                    {
-                        logf (LOG_LOG, "commit start");
-                        zebraIndexLockMsg ("c");
-                        zebraIndexWait (1);
-                        logf (LOG_LOG, "commit execute");
-                        bf_commitExec (rGroupDef.bfs);
-#ifndef WIN32
-                        sync ();
-#endif
-                        zebraIndexLockMsg ("d");
-                        zebraIndexWait (0);
-                        logf (LOG_LOG, "commit clean");
-                        bf_commitClean (rGroupDef.bfs, rval);
-                    }
-                    else
-                        logf (LOG_LOG, "nothing to commit");
+                    zebra_commit (zh);
                 }
                 else if (!strcmp (arg, "clean"))
                 {
-                    rval = res_get (common_resource, "shadow");
-                    zebraIndexLock (rGroupDef.bfs, 1, rval);
-                    if (bf_commitExists (rGroupDef.bfs))
-                    {
-                        zebraIndexLockMsg ("d");
-                        zebraIndexWait (0);
-                        logf (LOG_LOG, "commit clean");
-                        bf_commitClean (rGroupDef.bfs, rval);
-                    }
-                    else
-                        logf (LOG_LOG, "nothing to clean");
+                    assert (!"todo");
                 }
                 else if (!strcmp (arg, "stat") || !strcmp (arg, "status"))
                 {
-                   Records records;
-                    rval = res_get (common_resource, "shadow");
-                    zebraIndexLock (rGroupDef.bfs, 0, rval);
-                    if (rval && *rval)
-                    {
-                        bf_cache (rGroupDef.bfs, rval);
-                        zebraIndexLockMsg ("r");
-                    }
-                   records = rec_open (rGroupDef.bfs, 0, 0);
-                    rec_prstat (records);
-                   rec_close (&records);
-                    inv_prstat (rGroupDef.bfs);
+                    assert (!"todo");
                 }
                 else if (!strcmp (arg, "compact"))
                 {
-                    rval = res_get (common_resource, "shadow");
-                    zebraIndexLock (rGroupDef.bfs, 0, rval);
-                    if (rval && *rval)
-                    {
-                        bf_cache (rGroupDef.bfs, rval);
-                        zebraIndexLockMsg ("r");
-                    }
-                    inv_compact(rGroupDef.bfs);
+                    zebra_compact (zh);
                 }
                 else
                 {
@@ -240,81 +140,28 @@ int main (int argc, char **argv)
             }
            else
             {
-                struct recordGroup rGroup;
-#if ZMBOL
-#else
-               /* For zebra, delete lock file and reset register */
-               if (rGroupDef.flagRw)
-               {
-                   zebraIndexUnlock();
-                   bf_reset (rGroupDef.bfs);
-               }
-#endif
-                rval = res_get (common_resource, "shadow");
-                zebraIndexLock (rGroupDef.bfs, 0, rval);
-               if (rGroupDef.flagRw)
-               {
-                   if (rval && *rval && !disableCommit)
-                   {
-                       bf_cache (rGroupDef.bfs, rval);
-                       zebraIndexLockMsg ("r");
-                   }
-                   else
-                   {
-                       bf_cache (rGroupDef.bfs, 0);
-                       zebraIndexLockMsg ("w");
-                   }
-                   zebraIndexWait (0);
-               }
-                memcpy (&rGroup, &rGroupDef, sizeof(rGroup));
-                rGroup.path = arg;
+                memcpy (&zh->rGroup, &rGroupDef, sizeof(rGroupDef));
+                zebra_begin_trans (zh);
+
+                zh->rGroup.path = arg;
                 switch (cmd)
                 {
                 case 'u':
-                    if (!key_open (&rGroup, mem_max))
-                   {
-                       logf (LOG_LOG, "updating %s", rGroup.path);
-                       repositoryUpdate (&rGroup);
-                       nsections = key_close (&rGroup);
-                   }
-                    break;
-                case 'U':
-                    if (!key_open (&rGroup, mem_max))
-                   {
-                       logf (LOG_LOG, "updating (pass 1) %s", rGroup.path);
-                       repositoryUpdate (&rGroup);
-                       key_close (&rGroup);
-                   }
-                    nsections = 0;
+                    zebra_repository_update (zh);
                     break;
                 case 'd':
-                    if (!key_open (&rGroup,mem_max))
-                   {
-                       logf (LOG_LOG, "deleting %s", rGroup.path);
-                       repositoryDelete (&rGroup);
-                       nsections = key_close (&rGroup);
-                   }
+                    zebra_repository_delete (zh);
                     break;
                 case 's':
-                    logf (LOG_LOG, "dumping %s", rGroup.path);
-                    repositoryShow (&rGroup);
+                    logf (LOG_LOG, "dumping %s", zh->rGroup.path);
+                    zebra_repository_show (zh);
                     nsections = 0;
                     break;
-                case 'm':
-                    nsections = -1;
-                    break;
                 default:
                     nsections = 0;
                 }
                 cmd = 0;
-                if (nsections)
-                {
-                    logf (LOG_LOG, "merging with index");
-                    key_input (rGroup.bfs, nsections, 60, common_resource);
-#ifndef WIN32
-                    sync ();
-#endif
-                }
+                zebra_end_trans (zh);
                 log_event_end (NULL, NULL);
             }
         }
@@ -325,7 +172,7 @@ int main (int argc, char **argv)
 #else
             fprintf (stderr, "Zebra %s %s\n", ZEBRAVER, ZEBRADATE);
 #endif
-           fprintf (stderr, " (C) 1994-2001, Index Data ApS\n");
+           fprintf (stderr, " (C) 1994-2002, Index Data ApS\n");
 #ifdef WIN32
 #ifdef _DEBUG
             fprintf (stderr, " WIN32 Debug\n");
@@ -358,20 +205,11 @@ int main (int argc, char **argv)
             rGroupDef.recordType = arg;
         else if (ret == 'n')
             disableCommit = 1;
-#if ZEBRASDR
-       else if (ret == 'S')
-           rGroupDef.useSDR = 1;
-#endif
         else
             logf (LOG_WARN, "unknown option '-%s'", arg);
     }
-    recTypes_destroy (rGroupDef.recTypes);
-    if (common_resource)
-    {
-        zebraIndexUnlock ();
-       bfs_destroy (rGroupDef.bfs);
-    }
-    data1_destroy (rGroupDef.dh);
+    zebra_close (zh);
+    zebra_stop (zs);
     exit (0);
     return 0;
 }
index 150fc27..b855ead 100644 (file)
@@ -4,7 +4,10 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: trav.c,v $
- * Revision 1.36  1999-05-15 14:36:38  adam
+ * Revision 1.37  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.36  1999/05/15 14:36:38  adam
  * Updated dictionary. Implemented "compression" of dictionary.
  *
  * Revision 1.35  1999/02/02 14:51:09  adam
 #include <time.h>
 
 #include "index.h"
+#include "zserver.h"
 
 static int repComp (const char *a, const char *b, size_t len)
 {
@@ -159,7 +163,7 @@ static int repComp (const char *a, const char *b, size_t len)
     return memcmp (a, b, len);
 }
 
-static void repositoryExtractR (int deleteFlag, char *rep,
+static void repositoryExtractR (ZebraHandle zh, int deleteFlag, char *rep,
                                 struct recordGroup *rGroup,
                                int level)
 {
@@ -188,10 +192,10 @@ static void repositoryExtractR (int deleteFlag, char *rep,
         switch (e[i].kind)
         {
         case dirs_file:
-            fileExtract (NULL, rep, rGroup, deleteFlag);
+            fileExtract (zh, NULL, rep, rGroup, deleteFlag);
             break;
         case dirs_dir:
-            repositoryExtractR (deleteFlag, rep, rGroup, level+1);
+            repositoryExtractR (zh, deleteFlag, rep, rGroup, level+1);
             break;
         }
     }
@@ -199,9 +203,10 @@ static void repositoryExtractR (int deleteFlag, char *rep,
 
 }
 
-static void fileDeleteR (struct dirs_info *di, struct dirs_entry *dst,
-                              const char *base, char *src,
-                              struct recordGroup *rGroup)
+static void fileDeleteR (ZebraHandle zh,
+                         struct dirs_info *di, struct dirs_entry *dst,
+                         const char *base, char *src,
+                         struct recordGroup *rGroup)
 {
     char tmppath[1024];
     size_t src_len = strlen (src);
@@ -212,7 +217,7 @@ static void fileDeleteR (struct dirs_info *di, struct dirs_entry *dst,
         {
         case dirs_file:
             sprintf (tmppath, "%s%s", base, dst->path);
-            fileExtract (&dst->sysno, tmppath, rGroup, 1);
+            fileExtract (zh, &dst->sysno, tmppath, rGroup, 1);
              
             strcpy (tmppath, dst->path);
             dst = dirs_read (di); 
@@ -229,7 +234,8 @@ static void fileDeleteR (struct dirs_info *di, struct dirs_entry *dst,
     }
 }
 
-static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
+static void fileUpdateR (ZebraHandle zh,
+                         struct dirs_info *di, struct dirs_entry *dst,
                         const char *base, char *src, 
                         struct recordGroup *rGroup,
                         int level)
@@ -264,7 +270,7 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
     else if (!e_src)
     {
         strcpy (src, dst->path);
-        fileDeleteR (di, dst, base, src, rGroup);
+        fileDeleteR (zh, di, dst, base, src, rGroup);
         return;
     }
     else
@@ -311,7 +317,7 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
             case dirs_file:
                 if (e_src[i_src].mtime > dst->mtime)
                 {
-                    if (fileExtract (&dst->sysno, tmppath, rGroup, 0))
+                    if (fileExtract (zh, &dst->sysno, tmppath, rGroup, 0))
                     {
                         dirs_add (di, src, dst->sysno, e_src[i_src].mtime);
                     }
@@ -321,7 +327,7 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
                 dst = dirs_read (di);
                 break;
             case dirs_dir:
-                fileUpdateR (di, dst, base, src, rGroup, level+1);
+                fileUpdateR (zh, di, dst, base, src, rGroup, level+1);
                 dst = dirs_last (di);
                 logf (LOG_DEBUG, "last is %s", dst ? dst->path : "null");
                 break;
@@ -339,11 +345,11 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
             switch (e_src[i_src].kind)
             {
             case dirs_file:
-                if (fileExtract (&sysno, tmppath, rGroup, 0))
+                if (fileExtract (zh, &sysno, tmppath, rGroup, 0))
                     dirs_add (di, src, sysno, e_src[i_src].mtime);            
                 break;
             case dirs_dir:
-                fileUpdateR (di, dst, base, src, rGroup, level+1);
+                fileUpdateR (zh, di, dst, base, src, rGroup, level+1);
                 if (dst)
                     dst = dirs_last (di);
                 break;
@@ -358,12 +364,12 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
             switch (dst->kind)
             {
             case dirs_file:
-                fileExtract (&dst->sysno, tmppath, rGroup, 1);
+                fileExtract (zh, &dst->sysno, tmppath, rGroup, 1);
                 dirs_del (di, dst->path);
                 dst = dirs_read (di);
                 break;
             case dirs_dir:
-                fileDeleteR (di, dst, base, src, rGroup);
+                fileDeleteR (zh, di, dst, base, src, rGroup);
                 dst = dirs_last (di);
             }
         }
@@ -371,7 +377,7 @@ static void fileUpdateR (struct dirs_info *di, struct dirs_entry *dst,
     dir_free (&e_src);
 }
 
-static void groupRes (struct recordGroup *rGroup)
+static void groupRes (ZebraService zs, struct recordGroup *rGroup)
 {
     char resStr[256];
     char gPrefix[256];
@@ -382,21 +388,23 @@ static void groupRes (struct recordGroup *rGroup)
         sprintf (gPrefix, "%s.", rGroup->groupName);
 
     sprintf (resStr, "%srecordId", gPrefix);
-    rGroup->recordId = res_get (common_resource, resStr);
+    rGroup->recordId = res_get (zs->res, resStr);
     sprintf (resStr, "%sdatabasePath", gPrefix);
     rGroup->databaseNamePath =
-       atoi (res_get_def (common_resource, resStr, "0"));
+       atoi (res_get_def (zs->res, resStr, "0"));
 }
 
-void repositoryShow (struct recordGroup *rGroup)
+void repositoryShow (ZebraHandle zh)
+                     
 {
+    struct recordGroup *rGroup = &zh->rGroup;
     char src[1024];
     int src_len;
     struct dirs_entry *dst;
     Dict dict;
     struct dirs_info *di;
     
-    if (!(dict = dict_open (rGroup->bfs, FMATCH_DICT, 50, 0, 0)))
+    if (!(dict = dict_open (zh->service->bfs, FMATCH_DICT, 50, 0, 0)))
     {
         logf (LOG_FATAL, "dict_open fail of %s", FMATCH_DICT);
        return;
@@ -420,7 +428,8 @@ void repositoryShow (struct recordGroup *rGroup)
     dict_close (dict);
 }
 
-static void fileUpdate (Dict dict, struct recordGroup *rGroup,
+static void fileUpdate (ZebraHandle zh,
+                        Dict dict, struct recordGroup *rGroup,
                         const char *path)
 {
     struct dirs_info *di;
@@ -443,13 +452,13 @@ static void fileUpdate (Dict dict, struct recordGroup *rGroup,
         if (e_dst)
         {
             if (sbuf.st_mtime > e_dst->mtime)
-                if (fileExtract (&e_dst->sysno, src, rGroup, 0))
+                if (fileExtract (zh, &e_dst->sysno, src, rGroup, 0))
                     dirs_add (di, src, e_dst->sysno, sbuf.st_mtime);
         }
         else
         {
             SYSNO sysno = 0;
-            if (fileExtract (&sysno, src, rGroup, 0))
+            if (fileExtract (zh, &sysno, src, rGroup, 0))
                  dirs_add (di, src, sysno, sbuf.st_mtime);
         }
         dirs_free (&di);
@@ -463,7 +472,7 @@ static void fileUpdate (Dict dict, struct recordGroup *rGroup,
         }
         di = dirs_open (dict, src, rGroup->flagRw);
         *dst = '\0';
-        fileUpdateR (di, dirs_read (di), src, dst, rGroup, 0);
+        fileUpdateR (zh, di, dirs_read (di), src, dst, rGroup, 0);
         dirs_free (&di);
     }
     else
@@ -473,7 +482,8 @@ static void fileUpdate (Dict dict, struct recordGroup *rGroup,
 }
 
 
-static void repositoryExtract (int deleteFlag, struct recordGroup *rGroup,
+static void repositoryExtract (ZebraHandle zh,
+                               int deleteFlag, struct recordGroup *rGroup,
                                const char *path)
 {
     struct stat sbuf;
@@ -484,34 +494,36 @@ static void repositoryExtract (int deleteFlag, struct recordGroup *rGroup,
 
     stat (src, &sbuf);
     if (S_ISREG(sbuf.st_mode))
-        fileExtract (NULL, src, rGroup, deleteFlag);
+        fileExtract (zh, NULL, src, rGroup, deleteFlag);
     else if (S_ISDIR(sbuf.st_mode))
-       repositoryExtractR (deleteFlag, src, rGroup, 0);
+       repositoryExtractR (zh, deleteFlag, src, rGroup, 0);
     else
         logf (LOG_WARN, "Ignoring path %s", src);
 }
 
-static void repositoryExtractG (int deleteFlag, struct recordGroup *rGroup)
+static void repositoryExtractG (ZebraHandle zh,
+                                int deleteFlag, struct recordGroup *rGroup)
 {
     if (*rGroup->path == '\0' || !strcmp(rGroup->path, "-"))
     {
         char src[1024];
 
         while (scanf ("%s", src) == 1)
-            repositoryExtract (deleteFlag, rGroup, src);
+            repositoryExtract (zh, deleteFlag, rGroup, src);
     }
     else
-        repositoryExtract (deleteFlag, rGroup, rGroup->path);
+        repositoryExtract (zh, deleteFlag, rGroup, rGroup->path);
 }
 
-void repositoryUpdate (struct recordGroup *rGroup)
+void repositoryUpdate (ZebraHandle zh)
 {
-    groupRes (rGroup);
+    struct recordGroup *rGroup = &zh->rGroup;
+    groupRes (zh->service, rGroup);
     assert (rGroup->path);
     if (rGroup->recordId && !strcmp (rGroup->recordId, "file"))
     {
         Dict dict;
-        if (!(dict = dict_open (rGroup->bfs, FMATCH_DICT, 50,
+        if (!(dict = dict_open (zh->service->bfs, FMATCH_DICT, 50,
                                rGroup->flagRw, 0)))
         {
             logf (LOG_FATAL, "dict_open fail of %s", FMATCH_DICT);
@@ -521,18 +533,18 @@ void repositoryUpdate (struct recordGroup *rGroup)
         {
             char src[1024];
             while (scanf ("%s", src) == 1)
-                fileUpdate (dict, rGroup, src);
+                fileUpdate (zh, dict, rGroup, src);
         }
         else
-            fileUpdate (dict, rGroup, rGroup->path);
+            fileUpdate (zh, dict, rGroup, rGroup->path);
         dict_close (dict);
     }
     else 
-        repositoryExtractG (0, rGroup);
+        repositoryExtractG (zh, 0, rGroup);
 }
 
-void repositoryDelete (struct recordGroup *rGroup)
+void repositoryDelete (ZebraHandle zh)
 {
-    repositoryExtractG (1, rGroup);
+    repositoryExtractG (zh, 1, &zh->rGroup);
 }
 
index 3cd3a10..bb0c06f 100644 (file)
@@ -1,155 +1,8 @@
 /*
- * Copyright (C) 1995-2000, Index Data
+ * Copyright (C) 1995-2002, Index Data
  * All rights reserved.
  *
- * $Log: zebraapi.c,v $
- * Revision 1.44  2001-10-15 19:53:43  adam
- * POSIX thread updates. First work on term sets.
- *
- * Revision 1.43  2000/12/05 12:22:53  adam
- * Termlist source implemented (so that we can index values of XML/SGML
- * attributes).
- *
- * Revision 1.42  2000/12/05 10:01:44  adam
- * Fixed bug regarding user-defined attribute sets.
- *
- * Revision 1.41  2000/12/01 17:59:08  adam
- * Fixed bug regarding online updates on WIN32.
- * When zebra.cfg is not available the server will not abort.
- *
- * Revision 1.40  2000/11/29 15:21:31  adam
- * Fixed problem with passwd db.
- *
- * Revision 1.39  2000/11/29 14:24:01  adam
- * Script configure uses yaz pthreads options. Added locking for
- * zebra_register_{lock,unlock}.
- *
- * Revision 1.38  2000/11/08 13:46:58  adam
- * Fixed scan: server could break if bad attribute/database was selected.
- * Work on remote update.
- *
- * Revision 1.37  2000/10/17 12:37:09  adam
- * Fixed notification of live-updates. Fixed minor problem with mf_init
- * where it didn't handle shadow area file names correctly.
- *
- * Revision 1.36  2000/09/06 08:59:36  adam
- * Using read-only (for now) for server.
- *
- * Revision 1.35  2000/07/07 12:49:20  adam
- * Optimized resultSetInsert{Rank,Sort}.
- *
- * Revision 1.34  2000/06/09 13:56:38  ian
- * Added some logging on Authentication and searches.
- *
- * Revision 1.33  2000/05/18 12:01:36  adam
- * System call times(2) used again. More 64-bit fixes.
- *
- * Revision 1.32  2000/04/19 14:35:59  adam
- * WIN32 update (this version is known not to work on Windows).
- *
- * Revision 1.31  2000/04/05 10:07:02  adam
- * Minor zebra compile fix.
- *
- * Revision 1.30  2000/04/05 09:49:35  adam
- * On Unix, zebra/z'mbol uses automake.
- *
- * Revision 1.29  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.28  2000/03/15 15:00:30  adam
- * First work on threaded version.
- *
- * Revision 1.27  2000/02/24 12:31:17  adam
- * Added zebra_string_norm.
- *
- * Revision 1.26  1999/11/30 13:48:03  adam
- * Improved installation. Updated for inclusion of YAZ header files.
- *
- * Revision 1.25  1999/11/04 15:00:45  adam
- * Implemented delete result set(s).
- *
- * Revision 1.24  1999/10/14 14:33:50  adam
- * Added truncation 5=106.
- *
- * Revision 1.23  1999/09/07 11:36:32  adam
- * Minor changes.
- *
- * Revision 1.22  1999/08/02 10:13:47  adam
- * Fixed bug regarding zebra_hits.
- *
- * Revision 1.21  1999/07/14 10:59:26  adam
- * Changed functions isc_getmethod, isams_getmethod.
- * Improved fatal error handling (such as missing EXPLAIN schema).
- *
- * Revision 1.20  1999/07/06 12:28:04  adam
- * Updated record index structure. Format includes version ID. Compression
- * algorithm ID is stored for each record block.
- *
- * Revision 1.19  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.18  1999/05/15 14:36:38  adam
- * Updated dictionary. Implemented "compression" of dictionary.
- *
- * Revision 1.17  1999/05/12 13:08:06  adam
- * First version of ISAMS.
- *
- * Revision 1.16  1999/02/19 10:38:30  adam
- * Implemented chdir-setting.
- *
- * Revision 1.15  1999/02/17 12:18:12  adam
- * Fixed zebra_close so that a NULL pointer is ignored.
- *
- * Revision 1.14  1999/02/02 14:51:11  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.13  1998/12/16 12:23:30  adam
- * Added facility for database name mapping using resource mapdb.
- *
- * Revision 1.12  1998/11/16 10:18:10  adam
- * Better error reporting for result sets.
- *
- * Revision 1.11  1998/10/16 08:14:34  adam
- * Updated record control system.
- *
- * Revision 1.10  1998/09/22 10:03:42  adam
- * Changed result sets to be persistent in the sense that they can
- * be re-searched if needed.
- * Fixed memory leak in rsm_or.
- *
- * Revision 1.9  1998/09/02 13:53:17  adam
- * Extra parameter decode added to search routines to implement
- * persistent queries.
- *
- * Revision 1.8  1998/08/24 17:29:23  adam
- * Minor changes.
- *
- * Revision 1.7  1998/06/24 12:16:13  adam
- * Support for relations on text operands. Open range support in
- * DFA module (i.e. [-j], [g-]).
- *
- * Revision 1.6  1998/06/22 11:36:47  adam
- * Added authentication check facility to zebra.
- *
- * Revision 1.5  1998/06/13 00:14:08  adam
- * Minor changes.
- *
- * Revision 1.4  1998/06/12 12:22:12  adam
- * Work on Zebra API.
- *
- * Revision 1.3  1998/05/27 16:57:44  adam
- * Zebra returns surrogate diagnostic for single records when
- * appropriate.
- *
- * Revision 1.2  1998/05/20 10:12:19  adam
- * Implemented automatic EXPLAIN database maintenance.
- * Modified Zebra to work with ASN.1 compiled version of YAZ.
- *
- * Revision 1.1  1998/03/05 08:45:13  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
+ * $Id: zebraapi.c,v 1.45 2002-02-20 17:30:01 adam Exp $
  */
 
 #include <assert.h>
@@ -179,93 +32,23 @@ static void zebra_chdir (ZebraService zh)
 #endif
 }
 
-static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
-                              const char *buf, size_t buf_size,
-                              const char *databaseName, int delete_flag,
-                              int test_mode, int *sysno,
-                              int store_keys, int store_data,
-                              const char *match_criteria);
-
-static int explain_extract (void *handle, Record rec, data1_node *n);
-static void extract_index (ZebraHandle zh);
-
-static void zebra_register_unlock (ZebraHandle zh);
-
-static int zebra_register_activate (ZebraService zh, int rw);
-static int zebra_register_deactivate (ZebraService zh);
-
-static int zebra_register_lock (ZebraHandle zh, int rw)
+static void zebra_flush_reg (ZebraHandle zh)
 {
-    time_t lastChange;
-    int state;
-    zh->errCode = 0;
-    zh->errString = 0;
-    if (!zh->service->active)
-    {
-       zh->errCode = 1019;
-       return 1;
-    }
+    if (zh->service->matchDict)
+        dict_close (zh->service->matchDict);
+    zh->service->matchDict = 0;
+    zebraExplain_flush (zh->service->zei, 1, zh);
     
-#if HAVE_SYS_TIMES_H
-    times (&zh->tms1);
-#endif
-
-    zebra_mutex_cond_lock (&zh->service->session_lock);
-
-    state = zebra_server_lock_get_state(zh->service, &lastChange);
-
-    zebra_server_lock (zh->service, state);
-
-    switch (state)
-    {
-    case 'c':
-        state = 1;
-        break;
-    default:
-        state = 0;
-    }
-    if (rw)
-       logf (LOG_LOG, "Register in read/write mode");
-    else if (zh->service->registerState == state)
-    {
-        logf (LOG_DEBUG, "registerChange = %ld lastChange = %ld",
-            (long) zh->service->registerChange, (long)lastChange);
-       if (zh->service->registerChange >= lastChange)
-        {
-           return 0;
-        }
-       logf (LOG_LOG, "Register completely updated since last access");
-    }
-    else if (zh->service->registerState == -1)
-       logf (LOG_LOG, "Reading register using state %d pid=%ld", state,
-             (long) getpid());
-    else
-       logf (LOG_LOG, "Register has changed state from %d to %d",
-              zh->service->registerState, state);
-    zh->service->registerChange = lastChange;
-
-    zebra_register_deactivate (zh->service);
-
-    zh->service->registerState = state;
-
-    zebra_register_activate (zh->service, rw);
-    return 0;
+    extract_flushWriteKeys (zh);
+    zebra_index_merge (zh);
 }
 
 
-static void zebra_register_unlock (ZebraHandle zh)
-{
-    if (zh->service->registerState != -1)
-        zebra_server_unlock (zh->service, zh->service->registerState);
-    zebra_mutex_cond_unlock (&zh->service->session_lock);
-#if HAVE_SYS_TIMES_H
-    times (&zh->tms2);
-    logf (LOG_LOG, "user/system: %ld/%ld",
-                    (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
-                    (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
+static int zebra_register_activate (ZebraHandle zh, int rw, int useshadow);
+static int zebra_register_deactivate (ZebraHandle zh);
 
-#endif
-}
+static int zebra_begin_read (ZebraHandle zh);
+static void zebra_end_read (ZebraHandle zh);
 
 ZebraHandle zebra_open (ZebraService zs)
 {
@@ -284,9 +67,19 @@ ZebraHandle zebra_open (ZebraService zs)
     zh->errCode = 0;
     zh->errString = 0;
 
+    zh->trans_no = 0;
+    zh->seqno = 0;
+    zh->last_val = 0;
+
+    zh->lock_normal = zebra_lock_create ("norm.LCK", 0);
+    zh->lock_shadow = zebra_lock_create ("shadow.LCK", 0);
+
     zh->key_buf = 0;
     zh->admin_databaseName = 0;
-    
+
+    zh->keys.buf_max = 0;
+    zh->keys.buf = 0;
+
     zebra_mutex_cond_lock (&zs->session_lock);
 
     zh->next = zs->sessions;
@@ -318,7 +111,7 @@ ZebraService zebra_start (const char *configName)
 //     return zh;
     }
     zebra_chdir (zh);
-    zebra_server_lock_init (zh);
+
     zebra_mutex_cond_init (&zh->session_lock);
     if (!res_get (zh->res, "passwd"))
        zh->passwd_db = NULL;
@@ -334,115 +127,121 @@ ZebraService zebra_start (const char *configName)
     return zh;
 }
 
-static int zebra_register_activate (ZebraService zh, int rw)
+static int zebra_register_activate (ZebraHandle zh, int rw, int useshadow)
 {
-    if (zh->active > 1)
-    {
-       yaz_log (LOG_LOG, "zebra_register_activate (ignored since active=%d)",
-                zh->active);
-       return 0;
-    }
-    yaz_log (LOG_LOG, "zebra_register_activate shadow=%s",
-            zh->registerState ? "yes" : "no");
+    ZebraService zs = zh->service;
+    int record_compression = REC_COMPRESS_NONE;
+    char *recordCompression = 0;
+
+    yaz_log (LOG_LOG, "zebra_open_register_activate rw = %d useshadow=%d",
+             rw, useshadow);
 
-    zh->dh = data1_create ();
-    if (!zh->dh)
+    zs->dh = data1_create ();
+    if (!zs->dh)
         return -1;
-    zh->bfs = bfs_create (res_get (zh->res, "register"));
-    if (!zh->bfs)
+    zs->bfs = bfs_create (res_get (zs->res, "register"));
+    if (!zs->bfs)
     {
-        data1_destroy(zh->dh);
+        data1_destroy(zs->dh);
         return -1;
     }
-    bf_lockDir (zh->bfs, res_get (zh->res, "lockDir"));
-    bf_cache (zh->bfs, zh->registerState ? res_get (zh->res, "shadow") : NULL);
-    data1_set_tabpath (zh->dh, res_get(zh->res, "profilePath"));
-    zh->recTypes = recTypes_init (zh->dh);
-    recTypes_default_handlers (zh->recTypes);
-
-    zh->records = NULL;
-    zh->zebra_maps = zebra_maps_open (zh->res);
-    zh->rank_classes = NULL;
-
-    zh->records = 0;
-    zh->dict = 0;
-    zh->sortIdx = 0;
-    zh->isams = 0;
+    bf_lockDir (zs->bfs, res_get (zs->res, "lockDir"));
+    if (useshadow)
+        bf_cache (zs->bfs, res_get (zs->res, "shadow"));
+    data1_set_tabpath (zs->dh, res_get(zs->res, "profilePath"));
+    zs->recTypes = recTypes_init (zs->dh);
+    recTypes_default_handlers (zs->recTypes);
+
+    zs->records = NULL;
+    zs->zebra_maps = zebra_maps_open (zs->res);
+    zs->rank_classes = NULL;
+
+    zs->records = 0;
+    zs->dict = 0;
+    zs->sortIdx = 0;
+    zs->isams = 0;
 #if ZMBOL
-    zh->isam = 0;
-    zh->isamc = 0;
-    zh->isamd = 0;
+    zs->isam = 0;
+    zs->isamc = 0;
+    zs->isamd = 0;
 #endif
-    zh->zei = 0;
+    zs->zei = 0;
     
-    zebraRankInstall (zh, rank1_class);
+    zebraRankInstall (zs, rank1_class);
+
+    recordCompression = res_get_def (zh->service->res,
+                                    "recordCompression", "none");
+    if (!strcmp (recordCompression, "none"))
+       record_compression = REC_COMPRESS_NONE;
+    if (!strcmp (recordCompression, "bzip2"))
+       record_compression = REC_COMPRESS_BZIP2;
 
-    if (!(zh->records = rec_open (zh->bfs, rw, 0)))
+    if (!(zs->records = rec_open (zs->bfs, rw, record_compression)))
     {
        logf (LOG_WARN, "rec_open");
        return -1;
     }
-    if (!(zh->dict = dict_open (zh->bfs, FNAME_DICT, 80, rw, 0)))
+    if (!(zs->dict = dict_open (zs->bfs, FNAME_DICT, 80, rw, 0)))
     {
        logf (LOG_WARN, "dict_open");
        return -1;
     }
-    if (!(zh->sortIdx = sortIdx_open (zh->bfs, rw)))
+    if (!(zs->sortIdx = sortIdx_open (zs->bfs, rw)))
     {
        logf (LOG_WARN, "sortIdx_open");
        return -1;
     }
-    if (res_get_match (zh->res, "isam", "s", ISAM_DEFAULT))
+    if (res_get_match (zs->res, "isam", "s", ISAM_DEFAULT))
     {
        struct ISAMS_M_s isams_m;
-       if (!(zh->isams = isams_open (zh->bfs, FNAME_ISAMS, rw,
-                                     key_isams_m(zh->res, &isams_m))))
+       if (!(zs->isams = isams_open (zs->bfs, FNAME_ISAMS, rw,
+                                     key_isams_m(zs->res, &isams_m))))
        {
            logf (LOG_WARN, "isams_open");
            return -1;
        }
     }
 #if ZMBOL
-    else if (res_get_match (zh->res, "isam", "i", ISAM_DEFAULT))
+    else if (res_get_match (zs->res, "isam", "i", ISAM_DEFAULT))
     {
-       if (!(zh->isam = is_open (zh->bfs, FNAME_ISAM, key_compare, rw,
-                                 sizeof (struct it_key), zh->res)))
+       if (!(zs->isam = is_open (zs->bfs, FNAME_ISAM, key_compare, rw,
+                                 sizeof (struct it_key), zs->res)))
        {
            logf (LOG_WARN, "is_open");
            return -1;
        }
     }
-    else if (res_get_match (zh->res, "isam", "c", ISAM_DEFAULT))
+    else if (res_get_match (zs->res, "isam", "c", ISAM_DEFAULT))
     {
        struct ISAMC_M_s isamc_m;
-       if (!(zh->isamc = isc_open (zh->bfs, FNAME_ISAMC,
-                                   rw, key_isamc_m(zh->res, &isamc_m))))
+       if (!(zs->isamc = isc_open (zs->bfs, FNAME_ISAMC,
+                                   rw, key_isamc_m(zs->res, &isamc_m))))
        {
            logf (LOG_WARN, "isc_open");
            return -1;
        }
     }
-    else if (res_get_match (zh->res, "isam", "d", ISAM_DEFAULT))
+    else if (res_get_match (zs->res, "isam", "d", ISAM_DEFAULT))
     {
        struct ISAMD_M_s isamd_m;
        
-       if (!(zh->isamd = isamd_open (zh->bfs, FNAME_ISAMD,
-                                     rw, key_isamd_m(zh->res, &isamd_m))))
+       if (!(zs->isamd = isamd_open (zs->bfs, FNAME_ISAMD,
+                                     rw, key_isamd_m(zs->res, &isamd_m))))
        {
            logf (LOG_WARN, "isamd_open");
            return -1;
        }
     }
 #endif
-    zh->zei = zebraExplain_open (zh->records, zh->dh,
-                                zh->res, rw, 0 /* rGroup */,
+    zs->zei = zebraExplain_open (zs->records, zs->dh,
+                                zs->res, rw, zh,
                                 explain_extract);
-    if (!zh->zei)
+    if (!zs->zei)
     {
        logf (LOG_WARN, "Cannot obtain EXPLAIN information");
        return -1;
     }
-    zh->active = 2;
+    zs->active = 2;
     yaz_log (LOG_LOG, "zebra_register_activate ok");
     return 0;
 }
@@ -452,7 +251,7 @@ void zebra_admin_shutdown (ZebraHandle zh)
     zebra_mutex_cond_lock (&zh->service->session_lock);
     zh->service->stop_flag = 1;
     if (!zh->service->sessions)
-       zebra_register_deactivate(zh->service);
+       zebra_register_deactivate(zh);
     zh->service->active = 0;
     zebra_mutex_cond_unlock (&zh->service->session_lock);
 }
@@ -467,8 +266,9 @@ void zebra_admin_start (ZebraHandle zh)
     zebra_mutex_cond_unlock (&zs->session_lock);
 }
 
-static int zebra_register_deactivate (ZebraService zs)
+static int zebra_register_deactivate (ZebraHandle zh)
 {
+    ZebraService zs = zh->service;
     zs->stop_flag = 0;
     if (zs->active <= 1)
     {
@@ -495,6 +295,8 @@ static int zebra_register_deactivate (ZebraService zs)
 #endif
         rec_close (&zs->records);
     }
+    resultSetInvalidate (zh);
+
     recTypes_destroy (zs->recTypes);
     zebra_maps_close (zs->zebra_maps);
     zebraRankDestroy (zs);
@@ -515,13 +317,15 @@ void zebra_stop(ZebraService zs)
 
     zebra_mutex_cond_lock (&zs->session_lock);
     while (zs->sessions)
+    {
+        zebra_register_deactivate(zs->sessions);
         zebra_close (zs->sessions);
-
+    }
+        
     zebra_mutex_cond_unlock (&zs->session_lock);
 
     zebra_mutex_cond_destroy (&zs->session_lock);
 
-    zebra_register_deactivate(zs);
     res_close (zs->res);
     xfree (zs->configName);
     xfree (zs);
@@ -529,9 +333,13 @@ void zebra_stop(ZebraService zs)
 
 void zebra_close (ZebraHandle zh)
 {
-    ZebraService zs = zh->service;
+    ZebraService zs;
     struct zebra_session **sp;
 
+    if (!zh)
+        return;
+
+    zs = zh->service;
     yaz_log (LOG_LOG, "zebra_close zh=%p", zh);
     if (!zh)
        return ;
@@ -542,8 +350,11 @@ void zebra_close (ZebraHandle zh)
        xfree (zh->key_buf);
        zh->key_buf = 0;
     }
+    
     xfree (zh->admin_databaseName);
     zebra_mutex_cond_lock (&zs->session_lock);
+    zebra_lock_destroy (zh->lock_normal);
+    zebra_lock_destroy (zh->lock_shadow);
     sp = &zs->sessions;
     while (1)
     {
@@ -555,8 +366,8 @@ void zebra_close (ZebraHandle zh)
        }
        sp = &(*sp)->next;
     }
-    if (!zs->sessions && zs->stop_flag)
-       zebra_register_deactivate(zs);
+//    if (!zs->sessions && zs->stop_flag)
+//     zebra_register_deactivate(zs);
     zebra_mutex_cond_unlock (&zs->session_lock);
     xfree (zh);
 }
@@ -634,12 +445,12 @@ void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
                       const char *setname)
 {
     zh->hits = 0;
-    if (zebra_register_lock (zh, 0))
+    if (zebra_begin_read (zh))
        return;
     map_basenames (zh, stream, &num_bases, &basenames);
     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
 
-    zebra_register_unlock (zh);
+    zebra_end_read (zh);
 
     logf(LOG_APP,"SEARCH:%d:",zh->hits);
 }
@@ -652,8 +463,9 @@ void zebra_records_retrieve (ZebraHandle zh, ODR stream,
     ZebraPosSet poset;
     int i, *pos_array;
 
-    if (zebra_register_lock (zh, 0))
+    if (zebra_begin_read (zh))
        return;
+
     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
     for (i = 0; i<num_recs; i++)
        pos_array[i] = recs[i].position;
@@ -698,7 +510,7 @@ void zebra_records_retrieve (ZebraHandle zh, ODR stream,
        }
        zebraPosSetDestroy (zh, poset, num_recs);
     }
-    zebra_register_unlock (zh);
+    zebra_end_read (zh);
     xfree (pos_array);
 }
 
@@ -708,7 +520,7 @@ void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
                 int *position, int *num_entries, ZebraScanEntry **entries,
                 int *is_partial)
 {
-    if (zebra_register_lock (zh, 0))
+    if (zebra_begin_read (zh))
     {
        *entries = 0;
        *num_entries = 0;
@@ -718,7 +530,7 @@ void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
     rpn_scan (zh, stream, zapt, attributeset,
              num_bases, basenames, position,
              num_entries, entries, is_partial);
-    zebra_register_unlock (zh);
+    zebra_end_read (zh);
 }
 
 void zebra_sort (ZebraHandle zh, ODR stream,
@@ -726,11 +538,11 @@ void zebra_sort (ZebraHandle zh, ODR stream,
                 const char *output_setname, Z_SortKeySpecList *sort_sequence,
                 int *sort_status)
 {
-    if (zebra_register_lock (zh, 0))
+    if (zebra_begin_read (zh))
        return;
     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
                   output_setname, sort_sequence, sort_status);
-    zebra_register_unlock (zh);
+    zebra_end_read(zh);
 }
 
 int zebra_deleleResultSet(ZebraHandle zh, int function,
@@ -738,7 +550,7 @@ int zebra_deleleResultSet(ZebraHandle zh, int function,
                          int *statuses)
 {
     int i, status;
-    if (zebra_register_lock (zh, 0))
+    if (zebra_begin_read(zh))
        return Z_DeleteStatus_systemProblemAtTarget;
     switch (function)
     {
@@ -749,7 +561,7 @@ int zebra_deleleResultSet(ZebraHandle zh, int function,
        resultSetDestroy (zh, -1, 0, statuses);
        break;
     }
-    zebra_register_unlock (zh);
+    zebra_end_read (zh);
     status = Z_DeleteStatus_success;
     for (i = 0; i<num_setnames; i++)
        if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
@@ -791,17 +603,14 @@ int zebra_auth (ZebraService zh, const char *user, const char *pass)
 
 void zebra_admin_import_begin (ZebraHandle zh, const char *database)
 {
-    if (zebra_register_lock (zh, 1))
-       return;
+    zebra_begin_trans (zh);
     xfree (zh->admin_databaseName);
     zh->admin_databaseName = xstrdup(database);
 }
 
 void zebra_admin_import_end (ZebraHandle zh)
 {
-    zebraExplain_flush (zh->service->zei, 1, zh);
-    extract_index (zh);
-    zebra_register_unlock (zh);
+    zebra_end_trans (zh);
 }
 
 void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
@@ -844,21 +653,19 @@ void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
 
 void zebra_admin_create (ZebraHandle zh, const char *database)
 {
-    ZebraService zs = zh->service;
-    if (zebra_register_lock(zh, 1))
-    {
-       zh->errCode = 1019;
-       return;
-    }
+    ZebraService zs;
+
+    zebra_begin_trans (zh);
+
+    zs = zh->service;
     /* announce database */
-    if (zebraExplain_newDatabase (zs->zei, database, 0 /* explainDatabase */))
+    if (zebraExplain_newDatabase (zh->service->zei, database, 0 
+                                  /* explainDatabase */))
     {
        zh->errCode = 224;
        zh->errString = "Database already exist";
     }
-    zebraExplain_flush (zh->service->zei, 1, zh);
-    extract_index (zh);
-    zebra_register_unlock(zh);
+    zebra_end_trans (zh);
 }
 
 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
@@ -880,837 +687,296 @@ int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
     return wrbuf_len(wrbuf);
 }
 
-static void extract_init (struct recExtractCtrl *p, RecWord *w)
+
+void zebra_set_state (int val, int seqno)
 {
-    w->zebra_maps = p->zebra_maps;
-    w->seqnos = p->seqno;
-    w->attrSet = VAL_BIB1;
-    w->attrUse = 1016;
-    w->reg_type = 'w';
-    w->extractCtrl = p;
+    long p = getpid();
+    FILE *f = fopen ("state.LCK", "w");
+    fprintf (f, "%c %d %ld\n", val, seqno, p);
+    fclose (f);
 }
 
-static void extract_add_index_string (RecWord *p, const char *string,
-                                     int length)
+void zebra_get_state (char *val, int *seqno)
 {
-    char *dst;
-    unsigned char attrSet;
-    unsigned short attrUse;
-    int lead = 0;
-    int diff = 0;
-    int *pseqno = &p->seqnos[p->reg_type];
-    ZebraHandle zh = p->extractCtrl->handle;
-    ZebraExplainInfo zei = zh->service->zei;
-    struct recKeys *keys = &zh->keys;
-
-    if (keys->buf_used+1024 > keys->buf_max)
-    {
-        char *b;
-
-        b = (char *) xmalloc (keys->buf_max += 128000);
-        if (keys->buf_used > 0)
-            memcpy (b, keys->buf, keys->buf_used);
-        xfree (keys->buf);
-        keys->buf = b;
-    }
-    dst = keys->buf + keys->buf_used;
+    FILE *f = fopen ("state.LCK", "r");
 
-    attrSet = p->attrSet;
-    if (keys->buf_used > 0 && keys->prevAttrSet == attrSet)
-        lead |= 1;
-    else
-        keys->prevAttrSet = attrSet;
-    attrUse = p->attrUse;
-    if (keys->buf_used > 0 && keys->prevAttrUse == attrUse)
-        lead |= 2;
-    else
-        keys->prevAttrUse = attrUse;
-#if 1
-    diff = 1 + *pseqno - keys->prevSeqNo;
-    if (diff >= 1 && diff <= 15)
-        lead |= (diff << 2);
-    else
-        diff = 0;
-#endif
-    keys->prevSeqNo = *pseqno;
-    
-    *dst++ = lead;
-
-#if SU_SCHEME
-    if ((lead & 3) < 3)
-    {
-        int ch = zebraExplain_lookupSU (zei, attrSet, attrUse);
-        if (ch < 0)
-        {
-            ch = zebraExplain_addSU (zei, attrSet, attrUse);
-            yaz_log (LOG_LOG, "addSU set=%d use=%d SU=%d",
-                     attrSet, attrUse, ch);
-        }
-       assert (ch > 0);
-       memcpy (dst, &ch, sizeof(ch));
-       dst += sizeof(ch);
-    }
-#else
-    if (!(lead & 1))
-    {
-        memcpy (dst, &attrSet, sizeof(attrSet));
-        dst += sizeof(attrSet);
-    }
-    if (!(lead & 2))
-    {
-        memcpy (dst, &attrUse, sizeof(attrUse));
-        dst += sizeof(attrUse);
-    }
-#endif
-    *dst++ = p->reg_type;
-    memcpy (dst, string, length);
-    dst += length;
-    *dst++ = '\0';
+    *val = 'o';
+    *seqno = 0;
 
-    if (!diff)
+    if (f)
     {
-        memcpy (dst, pseqno, sizeof(*pseqno));
-        dst += sizeof(*pseqno);
+        fscanf (f, "%c %d", val, seqno);
+        fclose (f);
     }
-    keys->buf_used = dst - keys->buf;
-    if (*pseqno)
-       (*pseqno)++;
 }
 
-static void extract_add_sort_string (RecWord *p, const char *string,
-                                    int length)
+static int zebra_begin_read (ZebraHandle zh)
 {
-    struct sortKey *sk;
-    ZebraHandle zh = p->extractCtrl->handle;
-    struct sortKey *sortKeys = zh->sortKeys;
-
-    for (sk = sortKeys; sk; sk = sk->next)
-       if (sk->attrSet == p->attrSet && sk->attrUse == p->attrUse)
-           return;
-
-    sk = (struct sortKey *) xmalloc (sizeof(*sk));
-    sk->next = sortKeys;
-    sortKeys = sk;
-
-    sk->string = (char *) xmalloc (length);
-    sk->length = length;
-    memcpy (sk->string, string, length);
-
-    sk->attrSet = p->attrSet;
-    sk->attrUse = p->attrUse;
-}
+    int dirty = 0;
+    char val;
+    int seqno;
 
-static void extract_add_string (RecWord *p, const char *string, int length)
-{
-    assert (length > 0);
-    if (zebra_maps_is_sort (p->zebra_maps, p->reg_type))
-       extract_add_sort_string (p, string, length);
-    else
-       extract_add_index_string (p, string, length);
-}
+    zebra_flush_reg (zh);
 
-static void extract_add_incomplete_field (RecWord *p)
-{
-    const char *b = p->string;
-    int remain = p->length;
-    const char **map = 0;
+    (zh->trans_no)++;
 
-    if (remain > 0)
-       map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
+    if (zh->trans_no != 1)
+        return 0;
 
-    while (map)
+    zebra_get_state (&val, &seqno);
+    if (val == 'd')
+        val = 'o';
+    if (seqno != zh->seqno)
     {
-       char buf[IT_MAX_WORD+1];
-       int i, remain;
-
-       /* Skip spaces */
-       while (map && *map && **map == *CHR_SPACE)
-       {
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
-           else
-               map = 0;
-       }
-       if (!map)
-           break;
-       i = 0;
-       while (map && *map && **map != *CHR_SPACE)
-       {
-           const char *cp = *map;
-
-           while (i < IT_MAX_WORD && *cp)
-               buf[i++] = *(cp++);
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
-           else
-               map = 0;
-       }
-       if (!i)
-           return;
-       extract_add_string (p, buf, i);
+        yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d", seqno, zh->seqno);
+        dirty = 1;
     }
-    (p->seqnos[p->reg_type])++; /* to separate this from next one  */
-}
-
-static void extract_add_complete_field (RecWord *p)
-{
-    const char *b = p->string;
-    char buf[IT_MAX_WORD+1];
-    const char **map = 0;
-    int i = 0, remain = p->length;
-
-    if (remain > 0)
-       map = zebra_maps_input (p->zebra_maps, p->reg_type, &b, remain);
-
-    while (remain > 0 && i < IT_MAX_WORD)
+    else if (zh->last_val != val)
     {
-       while (map && *map && **map == *CHR_SPACE)
-       {
-           remain = p->length - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input(p->zebra_maps, p->reg_type, &b, remain);
-           else
-               map = 0;
-       }
-       if (!map)
-           break;
-
-       if (i && i < IT_MAX_WORD)
-           buf[i++] = *CHR_SPACE;
-       while (map && *map && **map != *CHR_SPACE)
-       {
-           const char *cp = *map;
-
-           if (i >= IT_MAX_WORD)
-               break;
-           while (i < IT_MAX_WORD && *cp)
-               buf[i++] = *(cp++);
-           remain = p->length  - (b - p->string);
-           if (remain > 0)
-               map = zebra_maps_input (p->zebra_maps, p->reg_type, &b,
-                                       remain);
-           else
-               map = 0;
-       }
+        yaz_log (LOG_LOG, "reopen last cur/old %d/%d", val, zh->last_val);
+        dirty = 1;
     }
-    if (!i)
-       return;
-    extract_add_string (p, buf, i);
-}
+    if (!dirty)
+        return 0;
 
-static void extract_token_add (RecWord *p)
-{
-    WRBUF wrbuf;
-    if ((wrbuf = zebra_replace(p->zebra_maps, p->reg_type, 0,
-                              p->string, p->length)))
-    {
-       p->string = wrbuf_buf(wrbuf);
-       p->length = wrbuf_len(wrbuf);
-    }
-    if (zebra_maps_is_complete (p->zebra_maps, p->reg_type))
-       extract_add_complete_field (p);
+    if (val == 'c')
+        zebra_lock_r (zh->lock_shadow);
     else
-       extract_add_incomplete_field(p);
-}
+        zebra_lock_r (zh->lock_normal);
+    
+    zh->last_val = val;
+    zh->seqno = seqno;
 
-static void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid)
-{
-    ZebraHandle zh = (ZebraHandle) (p->handle);
-    zebraExplain_addSchema (zh->service->zei, oid);
+    zebra_register_deactivate (zh);
+
+    zebra_register_activate (zh, 0, val == 'c' ? 1 : 0);
+    return 0;
 }
 
-static void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
-                                  int cmd, struct sortKey **skp)
+static void zebra_end_read (ZebraHandle zh)
 {
-    struct sortKey *sk = *skp;
-    SortIdx sortIdx = zh->service->sortIdx;
-
-    sortIdx_sysno (sortIdx, sysno);
-    while (sk)
-    {
-       struct sortKey *sk_next = sk->next;
-       sortIdx_type (sortIdx, sk->attrUse);
-       sortIdx_add (sortIdx, sk->string, sk->length);
-       xfree (sk->string);
-       xfree (sk);
-       sk = sk_next;
-    }
-    *skp = 0;
-}
+    (zh->trans_no)--;
 
-struct encode_info {
-    int  sysno;
-    int  seqno;
-    int  cmd;
-    char buf[768];
-};
+    if (zh->trans_no != 0)
+        return;
 
-void encode_key_init (struct encode_info *i)
-{
-    i->sysno = 0;
-    i->seqno = 0;
-    i->cmd = -1;
+    zebra_unlock (zh->lock_normal);
+    zebra_unlock (zh->lock_shadow);
 }
 
-char *encode_key_int (int d, char *bp)
+void zebra_begin_trans (ZebraHandle zh)
 {
-    if (d <= 63)
-        *bp++ = d;
-    else if (d <= 16383)
-    {
-        *bp++ = 64 + (d>>8);
-        *bp++ = d  & 255;
-    }
-    else if (d <= 4194303)
-    {
-        *bp++ = 128 + (d>>16);
-        *bp++ = (d>>8) & 255;
-        *bp++ = d & 255;
-    }
-    else
-    {
-        *bp++ = 192 + (d>>24);
-        *bp++ = (d>>16) & 255;
-        *bp++ = (d>>8) & 255;
-        *bp++ = d & 255;
-    }
-    return bp;
-}
+    int pass;
+    int seqno = 0;
+    char val = '?';
+    const char *rval;
 
-void encode_key_write (char *k, struct encode_info *i, FILE *outf)
-{
-    struct it_key key;
-    char *bp = i->buf;
-
-    while ((*bp++ = *k++))
-        ;
-    memcpy (&key, k+1, sizeof(struct it_key));
-    bp = encode_key_int ( (key.sysno - i->sysno) * 2 + *k, bp);
-    if (i->sysno != key.sysno)
-    {
-        i->sysno = key.sysno;
-        i->seqno = 0;
-    }
-    else if (!i->seqno && !key.seqno && i->cmd == *k)
-       return;
-    bp = encode_key_int (key.seqno - i->seqno, bp);
-    i->seqno = key.seqno;
-    i->cmd = *k;
-    if (fwrite (i->buf, bp - i->buf, 1, outf) != 1)
+    (zh->trans_no++);
+    if (zh->trans_no != 1)
     {
-        logf (LOG_FATAL|LOG_ERRNO, "fwrite");
-        exit (1);
+        return;
     }
-}
 
-static void extract_flushWriteKeys (ZebraHandle zh)
-{
-    FILE *outf;
-    char out_fname[200];
-    char *prevcp, *cp;
-    struct encode_info encode_info;
-    int ptr_i = zh->ptr_i;
-#if SORT_EXTRA
-    int i;
+    yaz_log (LOG_LOG, "zebra_begin_trans");
+#if HAVE_SYS_TIMES_H
+    times (&zh->tms1);
 #endif
-    if (!zh->key_buf || ptr_i <= 0)
-        return;
 
-    (zh->key_file_no)++;
-    logf (LOG_LOG, "sorting section %d", (zh->key_file_no));
-#if !SORT_EXTRA
-    qsort (zh->key_buf + zh->ptr_top - ptr_i, ptr_i, sizeof(char*),
-           key_qsort_compare);
-    extract_get_fname_tmp (zh, out_fname, zh->key_file_no);
+    /* lock */
+    rval = res_get (zh->service->res, "shadow");
 
-    if (!(outf = fopen (out_fname, "wb")))
-    {
-        logf (LOG_FATAL|LOG_ERRNO, "fopen %s", out_fname);
-        exit (1);
-    }
-    logf (LOG_LOG, "writing section %d", zh->key_file_no);
-    prevcp = cp = (zh->key_buf)[zh->ptr_top - ptr_i];
-    
-    encode_key_init (&encode_info);
-    encode_key_write (cp, &encode_info, outf);
-    
-    while (--ptr_i > 0)
+    for (pass = 0; pass < 2; pass++)
     {
-        cp = (zh->key_buf)[zh->ptr_top - ptr_i];
-        if (strcmp (cp, prevcp))
+        if (rval)
         {
-            encode_key_init (&encode_info);
-            encode_key_write (cp, &encode_info, outf);
-            prevcp = cp;
+            zebra_lock_r (zh->lock_normal);
+            zebra_lock_w (zh->lock_shadow);
         }
         else
-            encode_key_write (cp + strlen(cp), &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)
+            zebra_lock_w (zh->lock_normal);
+            zebra_lock_w (zh->lock_shadow);
+        }
+        
+        zebra_get_state (&val, &seqno);
+        if (val == 'c')
+        {
+            yaz_log (LOG_LOG, "previous transaction didn't finish commit");
+            zebra_unlock (zh->lock_shadow);
+            zebra_unlock (zh->lock_normal);
+            zebra_commit (zh);
+            continue;
+        }
+        else if (val == 'd')
+        {
+            if (rval)
             {
-                cp = key_buf[ptr_top-ptr_i];
-                encode_key_write (cp+key_y_len, &encode_info, outf);
+                BFiles bfs = bfs_create (res_get (zh->service->res, "shadow"));
+                yaz_log (LOG_LOG, "previous transaction didn't reach commit");
+                bf_commitClean (bfs, rval);
+                bfs_destroy (bfs);
+            }
+            else
+            {
+                yaz_log (LOG_WARN, "your previous transaction didn't finish");
             }
-            if (!i)
-                break;
-            prevcp = key_buf[ptr_top-ptr_i];
         }
-#endif
-    if (fclose (outf))
-    {
-        logf (LOG_FATAL|LOG_ERRNO, "fclose %s", out_fname);
-        exit (1);
+        break;
     }
-    logf (LOG_LOG, "finished section %d", zh->key_file_no);
-    zh->ptr_i = 0;
-    zh->key_buf_used = 0;
-}
-
-static void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
-                                    int cmd, struct recKeys *reckeys)
-{
-#if SU_SCHEME
-#else
-    unsigned char attrSet = (unsigned char) -1;
-    unsigned short attrUse = (unsigned short) -1;
-#endif
-    int seqno = 0;
-    int off = 0;
-    int ch = 0;
-    ZebraExplainInfo zei = zh->service->zei;
-
-    if (!zh->key_buf)
+    if (pass == 2)
     {
-       int mem = 8*1024*1024;
-       zh->key_buf = (char**) xmalloc (mem);
-       zh->ptr_top = mem/sizeof(char*);
-       zh->ptr_i = 0;
-       zh->key_buf_used = 0;
-       zh->key_file_no = 0;
+        yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
+        abort();
+        return;
     }
-    zebraExplain_recordCountIncrement (zei, cmd ? 1 : -1);
-    while (off < reckeys->buf_used)
-    {
-        const char *src = reckeys->buf + off;
-        struct it_key key;
-        int lead;
-    
-        lead = *src++;
+    zebra_set_state ('d', seqno);
 
-#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->key_buf_used + 1024 > (zh->ptr_top-zh->ptr_i)*sizeof(char*))
-            extract_flushWriteKeys (zh);
-        ++(zh->ptr_i);
-        (zh->key_buf)[zh->ptr_top - zh->ptr_i] =
-           (char*)zh->key_buf + zh->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->key_buf_used +=
-           key_SU_encode (ch,((char*)zh->key_buf) + zh->key_buf_used);
-
-        while (*src)
-            ((char*)zh->key_buf) [(zh->key_buf_used)++] = *src++;
-        src++;
-        ((char*)(zh->key_buf))[(zh->key_buf_used)++] = '\0';
-        ((char*)(zh->key_buf))[(zh->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->key_buf + zh->key_buf_used, &key, sizeof(key));
-        (zh->key_buf_used) += sizeof(key);
-        off = src - reckeys->buf;
-    }
-    assert (off == reckeys->buf_used);
+    zebra_register_activate (zh, 1, rval ? 1 : 0);
+    zh->service->matchDict = dict_open (zh->service->bfs, GMATCH_DICT,
+                                        50, 1, 0);
+    zh->seqno = seqno;
 }
 
-static void extract_index (ZebraHandle zh)
+void zebra_end_trans (ZebraHandle zh)
 {
-    extract_flushWriteKeys (zh);
-    zebra_index_merge (zh);
-}
+    char val;
+    int seqno;
+    const char *rval;
 
-static int explain_extract (void *handle, Record rec, data1_node *n)
-{
-    ZebraHandle zh = (ZebraHandle) handle;
-    struct recExtractCtrl extractCtrl;
-    int i;
+    zh->trans_no--;
+    if (zh->trans_no != 0)
+        return;
 
-    if (zebraExplain_curDatabase (zh->service->zei,
-                                 rec->info[recInfo_databaseName]))
-    {
-       abort();
-        if (zebraExplain_newDatabase (zh->service->zei,
-                                     rec->info[recInfo_databaseName], 0))
-            abort ();
-    }
+    yaz_log (LOG_LOG, "zebra_end_trans");
+    rval = res_get (zh->service->res, "shadow");
 
-    zh->keys.buf_used = 0;
-    zh->keys.prevAttrUse = -1;
-    zh->keys.prevAttrSet = -1;
-    zh->keys.prevSeqNo = 0;
-    zh->sortKeys = 0;
-    
-    extractCtrl.init = extract_init;
-    extractCtrl.tokenAdd = extract_token_add;
-    extractCtrl.schemaAdd = extract_schema_add;
-    extractCtrl.dh = zh->service->dh;
-    for (i = 0; i<256; i++)
-       extractCtrl.seqno[i] = 0;
-    extractCtrl.zebra_maps = zh->service->zebra_maps;
-    extractCtrl.flagShowRecords = 0;
-    extractCtrl.handle = handle;
-    
-    grs_extract_tree(&extractCtrl, n);
+    zebra_flush_reg (zh);
 
-    logf (LOG_LOG, "flush explain record, sysno=%d", rec->sysno);
+    zebra_register_deactivate (zh);
 
-    if (rec->size[recInfo_delKeys])
+    zebra_get_state (&val, &seqno);
+    if (val != 'd')
     {
-       struct recKeys delkeys;
-       struct sortKey *sortKeys = 0;
-
-       delkeys.buf_used = rec->size[recInfo_delKeys];
-       delkeys.buf = rec->info[recInfo_delKeys];
-       extract_flushSortKeys (zh, rec->sysno, 0, &sortKeys);
-       extract_flushRecordKeys (zh, rec->sysno, 0, &delkeys);
+        BFiles bfs = bfs_create (res_get (zh->service->res, "shadow"));
+        bf_commitClean (bfs, rval);
+        bfs_destroy (bfs);
     }
-    extract_flushRecordKeys (zh, rec->sysno, 1, &zh->keys);
-    extract_flushSortKeys (zh, rec->sysno, 1, &zh->sortKeys);
+    if (!rval)
+        seqno++;
+    zebra_set_state ('o', seqno);
 
-    xfree (rec->info[recInfo_delKeys]);
-    rec->size[recInfo_delKeys] = zh->keys.buf_used;
-    rec->info[recInfo_delKeys] = zh->keys.buf;
-    zh->keys.buf = NULL;
-    zh->keys.buf_max = 0;
-    return 0;
+    zebra_unlock (zh->lock_shadow);
+    zebra_unlock (zh->lock_normal);
+
+#if HAVE_SYS_TIMES_H
+    times (&zh->tms2);
+    logf (LOG_LOG, "user/system: %ld/%ld",
+                    (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
+                    (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
+
+#endif
 }
 
-static int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
-                              const char *buf, size_t buf_size,
-                              const char *databaseName, int delete_flag,
-                              int test_mode, int *sysno,
-                              int store_keys, int store_data,
-                              const char *match_criteria)
+void zebra_repository_update (ZebraHandle zh)
 {
-    RecordAttr *recordAttr;
-    struct recExtractCtrl extractCtrl;
-    int i, r;
-    RecType recType;
-    char subType[1024];
-    void *clientData;
-    const char *fname = "<no file>";
-    Record rec;
-    long recordOffset = 0;
-    struct zebra_fetch_control fc;
-
-    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;
+    zebra_begin_trans (zh);
+    logf (LOG_LOG, "updating %s", zh->rGroup.path);
+    repositoryUpdate (zh);    
+    zebra_end_trans (zh);
+}
 
-    /* announce database */
-    if (zebraExplain_curDatabase (zh->service->zei, databaseName))
-    {
-        if (zebraExplain_newDatabase (zh->service->zei, databaseName, 0))
-           return 0;
-    }
-    if (!(recType =
-         recType_byName (zh->service->recTypes, recordType, subType,
-                         &clientData)))
-    {
-        logf (LOG_WARN, "No such record type: %s", recordType);
-        return 0;
-    }
+void zebra_repository_delete (ZebraHandle zh)
+{
+    logf (LOG_LOG, "deleting %s", zh->rGroup.path);
+    repositoryDelete (zh);
+}
 
-    zh->keys.buf_used = 0;
-    zh->keys.prevAttrUse = -1;
-    zh->keys.prevAttrSet = -1;
-    zh->keys.prevSeqNo = 0;
-    zh->sortKeys = 0;
-
-    extractCtrl.subType = subType;
-    extractCtrl.init = extract_init;
-    extractCtrl.tokenAdd = extract_token_add;
-    extractCtrl.schemaAdd = extract_schema_add;
-    extractCtrl.dh = zh->service->dh;
-    extractCtrl.handle = zh;
-    extractCtrl.zebra_maps = zh->service->zebra_maps;
-    extractCtrl.flagShowRecords = 0;
-    for (i = 0; i<256; i++)
-    {
-       if (zebra_maps_is_positioned(zh->service->zebra_maps, i))
-           extractCtrl.seqno[i] = 1;
-       else
-           extractCtrl.seqno[i] = 0;
-    }
+void zebra_repository_show (ZebraHandle zh)
+{
+    repositoryShow (zh);
+}
 
-    r = (*recType->extract)(clientData, &extractCtrl);
+void zebra_commit (ZebraHandle zh)
+{
+    int seqno;
+    char val;
+    const char *rval = res_get (zh->service->res, "shadow");
+    BFiles bfs;
 
-    if (r == RECCTRL_EXTRACT_EOF)
-       return 0;
-    else if (r == RECCTRL_EXTRACT_ERROR)
-    {
-       /* error occured during extraction ... */
-#if 1
-       yaz_log (LOG_WARN, "extract error");
-#else
-       if (rGroup->flagRw &&
-           records_processed < rGroup->fileVerboseLimit)
-       {
-           logf (LOG_WARN, "fail %s %s %ld", rGroup->recordType,
-                 fname, (long) recordOffset);
-       }
-#endif
-       return 0;
-    }
-    if (zh->keys.buf_used == 0)
+    if (!rval)
     {
-       /* 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;
+        logf (LOG_WARN, "Cannot perform commit");
+        logf (LOG_WARN, "No shadow area defined");
+        return;
     }
-    /* match criteria */
 
-    if (! *sysno)
-    {
-        /* new record */
-        if (delete_flag)
-        {
-           logf (LOG_LOG, "delete %s %s %ld", recordType,
-                 fname, (long) recordOffset);
-            logf (LOG_WARN, "cannot delete record above (seems new)");
-            return 1;
-        }
-       logf (LOG_LOG, "add %s %s %ld", recordType, fname,
-             (long) recordOffset);
-        rec = rec_new (zh->service->records);
+    zebra_lock_w (zh->lock_normal);
+    zebra_lock_r (zh->lock_shadow);
 
-        *sysno = rec->sysno;
+    bfs = bfs_create (res_get (zh->service->res, "register"));
 
-       recordAttr = rec_init_attr (zh->service->zei, rec);
+    zebra_get_state (&val, &seqno);
 
-#if 0
-        if (matchStr)
-        {
-            dict_insert (matchDict, matchStr, sizeof(*sysno), sysno);
-        }
-#endif
-        extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
-       extract_flushSortKeys (zh, *sysno, 1, &zh->sortKeys);
-    }
-    else
+    if (rval && *rval)
+        bf_cache (bfs, rval);
+    if (bf_commitExists (bfs))
     {
-        /* record already exists */
-        struct recKeys delkeys;
-
-        rec = rec_get (zh->service->records, *sysno);
-        assert (rec);
-       
-       recordAttr = rec_init_attr (zh->service->zei, rec);
+        zebra_set_state ('c', seqno);
 
-       if (recordAttr->runNumber ==
-           zebraExplain_runNumberIncrement (zh->service->zei, 0))
-       {
-           logf (LOG_LOG, "skipped %s %s %ld", recordType,
-                 fname, (long) recordOffset);
-           rec_rm (&rec);
-           return 1;
-       }
-        delkeys.buf_used = rec->size[recInfo_delKeys];
-       delkeys.buf = rec->info[recInfo_delKeys];
-       extract_flushSortKeys (zh, *sysno, 0, &zh->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,
-                      fname, (long) recordOffset);
-                logf (LOG_WARN, "cannot delete file above, storeKeys false");
-            }
-            else
-            {
-               logf (LOG_LOG, "delete %s %s %ld", recordType,
-                     fname, (long) recordOffset);
-#if 0
-                if (matchStr)
-                    dict_delete (matchDict, matchStr);
+        logf (LOG_LOG, "commit start");
+        bf_commitExec (bfs);
+#ifndef WIN32
+        sync ();
 #endif
-                rec_del (zh->service->records, &rec);
-            }
-           rec_rm (&rec);
-            return 1;
-        }
-        else
-        {
-            /* record going to be updated */
-            if (!delkeys.buf_used)
-            {
-                logf (LOG_LOG, "update %s %s %ld", recordType,
-                      fname, (long) recordOffset);
-                logf (LOG_WARN, "cannot update file above, storeKeys false");
-            }
-            else
-            {
-               logf (LOG_LOG, "update %s %s %ld", recordType,
-                     fname, (long) recordOffset);
-                extract_flushRecordKeys (zh, *sysno, 1, &zh->keys);
-            }
-        }
-    }
-    /* 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->keys.buf_used > 0 && store_keys == 1)
-    {
-        rec->size[recInfo_delKeys] = zh->keys.buf_used;
-        rec->info[recInfo_delKeys] = zh->keys.buf;
-        zh->keys.buf = NULL;
-        zh->keys.buf_max = 0;
+        logf (LOG_LOG, "commit clean");
+        bf_commitClean (bfs, rval);
+        seqno++;
+        zebra_set_state ('o', seqno);
     }
     else
     {
-        rec->info[recInfo_delKeys] = NULL;
-        rec->size[recInfo_delKeys] = 0;
+        logf (LOG_LOG, "nothing to commit");
     }
+    bfs_destroy (bfs);
 
-    /* save file size of original record */
-    zebraExplain_recordBytesIncrement (zh->service->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->service->zei,
-                                      recordAttr->recordSize);
-
-    /* set run-number for this record */
-    recordAttr->runNumber =
-       zebraExplain_runNumberIncrement (zh->service->zei, 0);
+    zebra_unlock (zh->lock_shadow);
+    zebra_unlock (zh->lock_normal);
+}
 
-    /* update store data */
-    xfree (rec->info[recInfo_storeData]);
-    if (store_data == 1)
-    {
-        rec->size[recInfo_storeData] = recordAttr->recordSize;
-        rec->info[recInfo_storeData] = (char *)
-           xmalloc (recordAttr->recordSize);
-#if 1
-        memcpy (rec->info[recInfo_storeData], buf, recordAttr->recordSize);
-#else
-        if (lseek (fi->fd, recordOffset, SEEK_SET) < 0)
-        {
-            logf (LOG_ERRNO|LOG_FATAL, "seek to %ld in %s",
-                  (long) 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);
-        }
-#endif
-    }
-    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 (databaseName, &rec->size[recInfo_databaseName]); 
+void zebra_init (ZebraHandle zh)
+{
+    const char *rval = res_get (zh->service->res, "shadow");
+    BFiles bfs = 0;
 
-    /* update offset */
-    recordAttr->recordOffset = recordOffset;
+    bfs = bfs_create (res_get (zh->service->res, "register"));
+    if (rval && *rval)
+        bf_cache (bfs, rval);
     
-    /* commit this record */
-    rec_put (zh->service->records, &rec);
+    bf_reset (bfs);
+    bfs_destroy (bfs);
+    zebra_set_state ('o', 0);
+}
 
-    return 0;
+void zebra_compact (ZebraHandle zh)
+{
+    BFiles bfs = bfs_create (res_get (zh->service->res, "register"));
+    inv_compact (bfs);
+    bfs_destroy (bfs);
+}
+
+int zebra_record_insert (ZebraHandle zh, const char *buf, int len)
+{
+    int sysno = 0;
+    zebra_begin_trans (zh);
+    extract_rec_in_mem (zh, "grs.sgml",
+                        buf, len,
+                        "Default",  /* database */
+                        0 /* delete_flag */,
+                        0 /* test_mode */,
+                        &sysno /* sysno */,
+                        1 /* store_keys */,
+                        1 /* store_data */,
+                        0 /* match criteria */);
+    zebra_end_trans (zh);
+    return sysno;
 }
index 2935fef..8fe0dad 100644 (file)
@@ -1,49 +1,14 @@
 /*
- * Copyright (C) 1994-1998, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Log: zebraapi.h,v $
- * Revision 1.12  2000-04-05 09:49:35  adam
- * On Unix, zebra/z'mbol uses automake.
- *
- * Revision 1.11  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.10  2000/03/15 15:00:31  adam
- * First work on threaded version.
- *
- * Revision 1.9  2000/02/24 12:31:17  adam
- * Added zebra_string_norm.
- *
- * Revision 1.8  1999/11/30 13:48:03  adam
- * Improved installation. Updated for inclusion of YAZ header files.
- *
- * Revision 1.7  1999/11/04 15:00:45  adam
- * Implemented delete result set(s).
- *
- * Revision 1.6  1999/02/17 11:29:57  adam
- * Fixed in record_fetch. Minor updates to API.
- *
- * Revision 1.5  1998/09/22 10:48:19  adam
- * Minor changes in search API.
- *
- * Revision 1.4  1998/09/02 13:53:18  adam
- * Extra parameter decode added to search routines to implement
- * persistent queries.
- *
- * Revision 1.3  1998/06/22 11:36:48  adam
- * Added authentication check facility to zebra.
- *
- * Revision 1.2  1998/06/13 00:14:09  adam
- * Minor changes.
- *
- * Revision 1.1  1998/06/12 12:22:13  adam
- * Work on Zebra API.
- *
+ * $Id: zebraapi.h,v 1.13 2002-02-20 17:30:01 adam Exp $
  */
 
+#ifndef ZEBRAAPI_H
+#define ZEBRAAPI_H
+
 #include <yaz/odr.h>
 #include <yaz/oid.h>
 #include <yaz/proto.h>
@@ -137,4 +102,18 @@ YAZ_EXPORT void zebra_admin_import_segment (ZebraHandle zh,
                                            Z_Segment *segment);
 
 void zebra_admin_import_end (ZebraHandle zh);
+
+void zebra_begin_trans (ZebraHandle zh);
+void zebra_end_trans (ZebraHandle zh);
+
+void zebra_commit (ZebraHandle zh);
+
+void zebra_init (ZebraHandle zh);
+void zebra_compact (ZebraHandle zh);
+void zebra_repository_update (ZebraHandle zh);
+void zebra_repository_delete (ZebraHandle zh);
+void zebra_repository_show (ZebraHandle zh);
+int zebra_record_insert (ZebraHandle zh, const char *buf, int len);
+
 YAZ_END_CDECL                                
+#endif
index 0565a00..d91b11e 100644 (file)
@@ -1,85 +1,9 @@
 /*
- * Copyright (C) 1994-2000, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Log: zinfo.c,v $
- * Revision 1.22  2001-10-15 19:53:43  adam
- * POSIX thread updates. First work on term sets.
- *
- * Revision 1.21  2000/12/05 10:01:44  adam
- * Fixed bug regarding user-defined attribute sets.
- *
- * Revision 1.20  2000/11/29 14:24:01  adam
- * Script configure uses yaz pthreads options. Added locking for
- * zebra_register_{lock,unlock}.
- *
- * Revision 1.19  2000/07/07 12:49:20  adam
- * Optimized resultSetInsert{Rank,Sort}.
- *
- * Revision 1.18  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.17  1999/07/14 10:53:51  adam
- * Updated various routines to handle missing explain schema.
- *
- * Revision 1.16  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.15  1999/01/25 13:47:54  adam
- * Fixed bug.
- *
- * Revision 1.14  1998/11/04 16:31:32  adam
- * Fixed bug regarding recordBytes in databaseInfo.
- *
- * Revision 1.13  1998/11/03 10:17:09  adam
- * Fixed bug regarding creation of some data1 nodes for Explain records.
- *
- * Revision 1.12  1998/10/13 20:37:11  adam
- * Changed the way attribute sets are saved in Explain database to
- * reflect "dynamic" OIDs.
- *
- * Revision 1.11  1998/06/09 12:16:48  adam
- * Implemented auto-generation of CategoryList records.
- *
- * Revision 1.10  1998/06/08 14:43:15  adam
- * Added suport for EXPLAIN Proxy servers - added settings databasePath
- * and explainDatabase to facilitate this. Increased maximum number
- * of databases and attributes in one register.
- *
- * Revision 1.9  1998/06/02 12:10:27  adam
- * Fixed bug related to attributeDetails.
- *
- * Revision 1.8  1998/05/20 10:12:20  adam
- * Implemented automatic EXPLAIN database maintenance.
- * Modified Zebra to work with ASN.1 compiled version of YAZ.
- *
- * Revision 1.7  1998/03/05 08:45:13  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.6  1998/02/17 10:29:27  adam
- * Moved towards 'automatic' EXPLAIN database.
- *
- * Revision 1.5  1997/10/27 14:33:05  adam
- * Moved towards generic character mapping depending on "structure"
- * field in abstract syntax file. Fixed a few memory leaks. Fixed
- * bug with negative integers when doing searches with relational
- * operators.
- *
- * Revision 1.4  1997/09/25 14:57:08  adam
- * Added string.h.
- *
- * Revision 1.3  1996/05/22 08:21:59  adam
- * Added public ZebDatabaseInfo structure.
- *
- * Revision 1.2  1996/05/14 06:16:41  adam
- * Compact use/set bytes used in search service.
- *
- * Revision 1.1  1996/05/13 14:23:07  adam
- * Work on compaction of set/use bytes in dictionary.
- *
+ * $Id: zinfo.c,v 1.23 2002-02-20 17:30:01 adam Exp $
  */
 
 #include <stdlib.h>
index c17271e..4195dd1 100644 (file)
@@ -4,7 +4,10 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: zinfo.h,v $
- * Revision 1.11  2001-10-15 19:53:43  adam
+ * Revision 1.12  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.11  2001/10/15 19:53:43  adam
  * POSIX thread updates. First work on term sets.
  *
  * Revision 1.10  2000/05/15 12:56:37  adam
@@ -47,6 +50,7 @@
 #define ZINFO_H
 
 #include <yaz/data1.h>
+#include "zebraapi.h"
 #include "recindex.h"
 
 YAZ_BEGIN_CDECL
index c2642c7..1df6afd 100644 (file)
@@ -2,288 +2,7 @@
  * Copyright (C) 1995-2000, Index Data 
  * All rights reserved.
  *
- * $Log: zserver.c,v $
- * Revision 1.82  2001-07-09 23:40:09  adam
- * WIN32 fix.
- *
- * Revision 1.81  2001/02/14 21:42:07  adam
- * Fixed versions as returned in INIT response.
- *
- * Revision 1.80  2000/09/05 14:04:05  adam
- * Updates for prefix 'yaz_' for YAZ log functions.
- *
- * Revision 1.79  2000/05/09 10:56:50  adam
- * Added call to xmalloc/nmem debugging functions.
- *
- * Revision 1.78  2000/04/05 09:49:35  adam
- * On Unix, zebra/z'mbol uses automake.
- *
- * Revision 1.77  2000/03/20 19:08:36  adam
- * Added remote record import using Z39.50 extended services and Segment
- * Requests.
- *
- * Revision 1.76  2000/03/15 15:00:31  adam
- * First work on threaded version.
- *
- * Revision 1.75  1999/11/30 13:48:04  adam
- * Improved installation. Updated for inclusion of YAZ header files.
- *
- * Revision 1.74  1999/11/29 15:13:26  adam
- * Server sets implementationName - and Version.
- *
- * Revision 1.73  1999/11/04 15:00:45  adam
- * Implemented delete result set(s).
- *
- * Revision 1.71  1999/07/14 10:59:26  adam
- * Changed functions isc_getmethod, isams_getmethod.
- * Improved fatal error handling (such as missing EXPLAIN schema).
- *
- * Revision 1.70  1999/06/10 12:14:56  adam
- * Fixed to use bend_start instead of pre_init.
- *
- * Revision 1.69  1999/06/10 09:20:03  adam
- * Minor change to pre_init handler.
- *
- * Revision 1.68  1999/05/26 07:49:13  adam
- * C++ compilation.
- *
- * Revision 1.67  1999/02/02 14:51:14  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.66  1998/10/28 10:54:41  adam
- * SDRKit integration.
- *
- * Revision 1.65  1998/10/18 07:54:54  adam
- * Additional info added for diagnostics 114 (Unsupported use attribute) and
- * 121 (Unsupported attribute set).
- *
- * Revision 1.64  1998/09/22 10:48:21  adam
- * Minor changes in search API.
- *
- * Revision 1.63  1998/09/02 13:53:21  adam
- * Extra parameter decode added to search routines to implement
- * persistent queries.
- *
- * Revision 1.62  1998/08/06 14:35:28  adam
- * Routine bend_deleterequest removed.
- *
- * Revision 1.61  1998/06/24 12:16:15  adam
- * Support for relations on text operands. Open range support in
- * DFA module (i.e. [-j], [g-]).
- *
- * Revision 1.60  1998/06/22 11:36:49  adam
- * Added authentication check facility to zebra.
- *
- * Revision 1.59  1998/06/12 12:22:13  adam
- * Work on Zebra API.
- *
- * Revision 1.58  1998/05/27 16:57:46  adam
- * Zebra returns surrogate diagnostic for single records when
- * appropriate.
- *
- * Revision 1.57  1998/04/03 14:45:18  adam
- * Fixed setting of last_in_set in bend_fetch.
- *
- * Revision 1.56  1998/03/05 08:45:13  adam
- * New result set model and modular ranking system. Moved towards
- * descent server API. System information stored as "SGML" records.
- *
- * Revision 1.55  1998/02/10 12:03:06  adam
- * Implemented Sort.
- *
- * Revision 1.54  1998/01/29 13:39:13  adam
- * Compress ISAM is default.
- *
- * Revision 1.53  1998/01/12 15:04:09  adam
- * The test option (-s) only uses read-lock (and not write lock).
- *
- * Revision 1.52  1997/11/18 10:05:08  adam
- * Changed character map facility so that admin can specify character
- * mapping files for each register type, w, p, etc.
- *
- * Revision 1.51  1997/10/27 14:33:06  adam
- * Moved towards generic character mapping depending on "structure"
- * field in abstract syntax file. Fixed a few memory leaks. Fixed
- * bug with negative integers when doing searches with relational
- * operators.
- *
- * Revision 1.50  1997/09/29 09:08:36  adam
- * Revised locking system to be thread safe for the server.
- *
- * Revision 1.49  1997/09/25 14:57:23  adam
- * Windows NT port.
- *
- * Revision 1.48  1997/09/17 12:19:19  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.47  1997/09/04 13:58:36  adam
- * New retrieve/extract method tellf (added).
- * Added O_BINARY for open calls.
- *
- * Revision 1.46  1997/07/28 08:30:47  adam
- * Server returns diagnostic 14 when record doesn't exist.
- *
- * Revision 1.45  1996/12/23 15:30:45  adam
- * Work on truncation.
- * Bug fix: result sets weren't deleted after server shut down.
- *
- * Revision 1.44  1996/12/11 12:08:01  adam
- * Added better compression.
- *
- * Revision 1.43  1996/11/15 15:03:58  adam
- * Logging of execution speed by using the times(2) call.
- *
- * Revision 1.42  1996/11/08  11:10:36  adam
- * Buffers used during file match got bigger.
- * Compressed ISAM support everywhere.
- * Bug fixes regarding masking characters in queries.
- * Redesigned Regexp-2 queries.
- *
- * Revision 1.41  1996/10/29 14:09:56  adam
- * Use of cisam system - enabled if setting isamc is 1.
- *
- * Revision 1.40  1996/06/04 10:19:02  adam
- * Minor changes - removed include of ctype.h.
- *
- * Revision 1.39  1996/05/31  09:07:05  quinn
- * Work on character-set handling
- *
- * Revision 1.38  1996/05/14  11:34:01  adam
- * Scan support in multiple registers/databases.
- *
- * Revision 1.37  1996/05/14  06:16:48  adam
- * Compact use/set bytes used in search service.
- *
- * Revision 1.36  1996/05/01 13:46:37  adam
- * First work on multiple records in one file.
- * New option, -offset, to the "unread" command in the filter module.
- *
- * Revision 1.35  1996/03/26  16:01:14  adam
- * New setting lockPath: directory of various lock files.
- *
- * Revision 1.34  1996/03/20  09:36:46  adam
- * Function dict_lookup_grep got extra parameter, init_pos, which marks
- * from which position in pattern approximate pattern matching should occur.
- * Approximate pattern matching is used in relevance=re-2.
- *
- * Revision 1.33  1996/01/17  14:57:56  adam
- * Prototype changed for reader functions in extract/retrieve. File
- *  is identified by 'void *' instead of 'int.
- *
- * Revision 1.32  1995/12/11  09:12:58  adam
- * The rec_get function returns NULL if record doesn't exist - will
- * happen in the server if the result set records have been deleted since
- * the creation of the set (i.e. the search).
- * The server saves a result temporarily if it is 'volatile', i.e. the
- * set is register dependent.
- *
- * Revision 1.31  1995/12/08  16:22:56  adam
- * Work on update while servers are running. Three lock files introduced.
- * The servers reload their registers when necessary, but they don't
- * reestablish result sets yet.
- *
- * Revision 1.30  1995/12/07  17:38:48  adam
- * Work locking mechanisms for concurrent updates/commit.
- *
- * Revision 1.29  1995/12/04  14:22:32  adam
- * Extra arg to recType_byName.
- * Started work on new regular expression parsed input to
- * structured records.
- *
- * Revision 1.28  1995/11/28  09:09:48  adam
- * Zebra config renamed.
- * Use setting 'recordId' to identify record now.
- * Bug fix in recindex.c: rec_release_blocks was invokeded even
- * though the blocks were already released.
- * File traversal properly deletes records when needed.
- *
- * Revision 1.27  1995/11/27  13:58:54  adam
- * New option -t. storeStore data implemented in server.
- *
- * Revision 1.26  1995/11/25  10:24:07  adam
- * More record fields - they are enumerated now.
- * New options: flagStoreData flagStoreKey.
- *
- * Revision 1.25  1995/11/21  15:29:13  adam
- * Config file 'base' read by default by both indexer and server.
- *
- * Revision 1.24  1995/11/20  16:59:47  adam
- * New update method: the 'old' keys are saved for each records.
- *
- * Revision 1.23  1995/11/16  17:00:56  adam
- * Better logging of rpn query.
- *
- * Revision 1.22  1995/11/16  15:34:55  adam
- * Uses new record management system in both indexer and server.
- *
- * Revision 1.21  1995/11/01  16:25:52  quinn
- * *** empty log message ***
- *
- * Revision 1.20  1995/10/27  14:00:12  adam
- * Implemented detection of database availability.
- *
- * Revision 1.19  1995/10/17  18:02:11  adam
- * New feature: databases. Implemented as prefix to words in dictionary.
- *
- * Revision 1.18  1995/10/16  14:03:09  quinn
- * Changes to support element set names and espec1
- *
- * Revision 1.17  1995/10/16  09:32:40  adam
- * More work on relational op.
- *
- * Revision 1.16  1995/10/13  12:26:44  adam
- * Optimization of truncation.
- *
- * Revision 1.15  1995/10/12  12:40:55  adam
- * Bug fixes in rpn_prox.
- *
- * Revision 1.14  1995/10/09  16:18:37  adam
- * Function dict_lookup_grep got extra client data parameter.
- *
- * Revision 1.13  1995/10/06  14:38:00  adam
- * New result set method: r_score.
- * Local no (sysno) and score is transferred to retrieveCtrl.
- *
- * Revision 1.12  1995/10/06  13:52:06  adam
- * Bug fixes. Handler may abort further scanning.
- *
- * Revision 1.11  1995/10/06  10:43:57  adam
- * Scan added. 'occurrences' in scan entries not set yet.
- *
- * Revision 1.10  1995/10/02  16:43:32  quinn
- * Set default resulting record type in fetch.
- *
- * Revision 1.9  1995/10/02  15:18:52  adam
- * New member in recRetrieveCtrl: diagnostic.
- *
- * Revision 1.8  1995/09/28  09:19:47  adam
- * xfree/xmalloc used everywhere.
- * Extract/retrieve method seems to work for text records.
- *
- * Revision 1.7  1995/09/27  16:17:32  adam
- * More work on retrieve.
- *
- * Revision 1.6  1995/09/08  08:53:22  adam
- * Record buffer maintained in server_info.
- *
- * Revision 1.5  1995/09/06  16:11:18  adam
- * Option: only one word key per file.
- *
- * Revision 1.4  1995/09/06  10:33:04  adam
- * More work on present. Some log messages removed.
- *
- * Revision 1.3  1995/09/05  15:28:40  adam
- * More work on search engine.
- *
- * Revision 1.2  1995/09/04  12:33:43  adam
- * Various cleanup. YAZ util used instead.
- *
- * Revision 1.1  1995/09/04  09:10:41  adam
- * More work on index add/del/update.
- * Merge sort implemented.
- * Initial work on z39 server.
- *
+ * $Id: zserver.c,v 1.83 2002-02-20 17:30:01 adam Exp $
  */
 
 #include <stdio.h>
index d0c936b..77c7db6 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * Copyright (C) 1994-2001, Index Data 
+ * Copyright (C) 1994-2002, Index Data 
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Id: zserver.h,v 1.51 2001-10-15 19:53:43 adam Exp $
+ * $Id: zserver.h,v 1.52 2002-02-20 17:30:01 adam Exp $
  */
 
 #if HAVE_SYS_TIMES_H
@@ -47,6 +47,7 @@ struct zebra_service {
     ISAMD isamd;
 #endif
     Dict dict;
+    Dict matchDict;
     SortIdx sortIdx;
     int registerState; /* 0 (no commit pages), 1 (use commit pages) */
     time_t registerChange;
@@ -56,6 +57,7 @@ struct zebra_service {
     Res res;
     ZebraLockHandle server_lock_cmt;
     ZebraLockHandle server_lock_org;
+
     char *server_path_prefix;
     data1_handle dh;
     ZebraMaps zebra_maps;
@@ -98,6 +100,12 @@ struct zebra_session {
     int key_file_no;
     char *admin_databaseName;
 
+    ZebraLockHandle lock_normal;
+    ZebraLockHandle lock_shadow;
+
+    int trans_no;
+    int seqno;
+    int last_val;
     int destroyed;
     ZebraSet sets;
     int errCode;
@@ -107,6 +115,7 @@ struct zebra_session {
     struct tms tms1;
     struct tms tms2;    
 #endif
+    struct recordGroup rGroup;
 };
 
 struct rank_control {
@@ -167,6 +176,7 @@ void resultSetSortSingle (ZebraHandle zh, NMEM nmem,
                          ZebraSet sset, RSET rset,
                          Z_SortKeySpecList *sort_sequence, int *sort_status);
 void resultSetRank (ZebraHandle zh, ZebraSet zebraSet, RSET rset);
+void resultSetInvalidate (ZebraHandle zh);
 
 void zebra_sort (ZebraHandle zh, ODR stream,
                 int num_input_setnames, const char **input_setnames,
@@ -202,6 +212,15 @@ void extract_get_fname_tmp (ZebraHandle zh, char *fname, int no);
 void zebra_index_merge (ZebraHandle zh);
 
 
+int extract_rec_in_mem (ZebraHandle zh, const char *recordType,
+                        const char *buf, size_t buf_size,
+                        const char *databaseName, int delete_flag,
+                        int test_mode, int *sysno,
+                        int store_keys, int store_data,
+                        const char *match_criteria);
+
+void extract_flushWriteKeys (ZebraHandle zh);
+
 struct zebra_fetch_control {
     off_t offset_end;
     off_t record_offset;
@@ -219,4 +238,12 @@ off_t zebra_record_int_tell (void *fh);
 int zebra_record_int_read (void *fh, char *buf, size_t count);
 void zebra_record_int_end (void *fh, off_t offset);
 
+void extract_flushRecordKeys (ZebraHandle zh, SYSNO sysno,
+                              int cmd, struct recKeys *reckeys);
+void extract_flushSortKeys (ZebraHandle zh, SYSNO sysno,
+                            int cmd, struct sortKey **skp);
+void extract_schema_add (struct recExtractCtrl *p, Odr_oid *oid);
+void extract_token_add (RecWord *p);
+int explain_extract (void *handle, Record rec, data1_node *n);
+
 YAZ_END_CDECL
index dfb73e7..2fed59c 100644 (file)
@@ -4,7 +4,10 @@
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: zsets.c,v $
- * Revision 1.31  2001-11-19 23:05:22  adam
+ * Revision 1.32  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.31  2001/11/19 23:05:22  adam
  * Added a few prototypes.
  *
  * Revision 1.30  2001/10/15 19:53:43  adam
@@ -275,6 +278,7 @@ ZebraSet resultSetGet (ZebraHandle zh, const char *name)
             if (!s->term_entries && !s->rset && s->rpn)
             {
                 NMEM nmem = nmem_create ();
+                yaz_log (LOG_LOG, "research %s", name);
                 s->rset =
                     rpn_search (zh, nmem, s->rpn, s->num_bases,
                                s->basenames, s->name, s);
@@ -285,9 +289,21 @@ ZebraSet resultSetGet (ZebraHandle zh, const char *name)
     return NULL;
 }
 
+void resultSetInvalidate (ZebraHandle zh)
+{
+    ZebraSet s = zh->sets;
+    
+    for (; s; s = s->next)
+    {
+        if (s->rset)
+            rset_delete (s->rset);
+        s->rset = 0;
+    }
+}
+
 void resultSetDestroy (ZebraHandle zh, int num, char **names,int *statuses)
 {
-    ZebraSet *ss = &zh->sets;
+    ZebraSet * ss = &zh->sets;
     int i;
     
     if (statuses)
index d23a3d7..57b144b 100644 (file)
@@ -3,7 +3,10 @@
  * All rights reserved.
  *
  * $Log: recgrs.c,v $
- * Revision 1.41  2001-05-22 21:01:47  adam
+ * Revision 1.42  2002-02-20 17:30:01  adam
+ * Work on new API. Locking system re-implemented
+ *
+ * Revision 1.41  2001/05/22 21:01:47  adam
  * Removed print of data1 tree on stdout so that inetd works again.
  *
  * Revision 1.40  2001/03/29 21:31:31  adam
@@ -511,6 +514,9 @@ static int grs_extract_sub(struct grs_handlers *h, struct recExtractCtrl *p,
     if ((oid_ent_to_oid (&oe, oidtmp)))
        (*p->schemaAdd)(p, oidtmp);
 
+#if 0
+    data1_pr_tree (p->dh, n, stdout);
+#endif
     if (dumpkeys(n, p, 0) < 0)
     {
        data1_free_tree(p->dh, n);
index fe30044..0ab65fc 100644 (file)
@@ -1,98 +1,9 @@
 /*
- * Copyright (C) 1994-1999, Index Data
+ * Copyright (C) 1994-2002, Index Data
  * All rights reserved.
  * Sebastian Hammer, Adam Dickmeiss
  *
- * $Log: rstemp.c,v $
- * Revision 1.26  1999-05-26 07:49:14  adam
- * C++ compilation.
- *
- * Revision 1.25  1999/02/02 14:51:37  adam
- * Updated WIN32 code specific sections. Changed header.
- *
- * Revision 1.24  1998/03/05 08:36:28  adam
- * New result set model.
- *
- * Revision 1.23  1997/12/18 10:54:25  adam
- * New method result set method rs_hits that returns the number of
- * hits in result-set (if known). The ranked result set returns real
- * number of hits but only when not combined with other operands.
- *
- * Revision 1.22  1997/10/31 12:38:12  adam
- * Bug fix: added missing xfree() call.
- *
- * Revision 1.21  1997/09/17 12:19:23  adam
- * Zebra version corresponds to YAZ version 1.4.
- * Changed Zebra server so that it doesn't depend on global common_resource.
- *
- * Revision 1.20  1997/09/09 13:38:17  adam
- * Partial port to WIN95/NT.
- *
- * Revision 1.19  1997/09/04 13:58:57  adam
- * Added O_BINARY for open calls.
- *
- * Revision 1.18  1996/10/29 13:54:52  adam
- * Changed name of setting tempSetDir to setTmpDir.
- *
- * Revision 1.17  1995/12/11 09:15:28  adam
- * New set types: sand/sor/snot - ranked versions of and/or/not in
- * ranked/semi-ranked result sets.
- * Note: the snot not finished yet.
- * New rset member: flag.
- * Bug fix: r_delete in rsrel.c did free bad memory block.
- *
- * Revision 1.16  1995/11/28  14:47:02  adam
- * New setting: tempSetPath. Location of temporary result sets.
- *
- * Revision 1.15  1995/10/12  12:41:58  adam
- * Private info (buf) moved from struct rset_control to struct rset.
- * Bug fixes in relevance.
- *
- * Revision 1.14  1995/10/10  14:00:04  adam
- * Function rset_open changed its wflag parameter to general flags.
- *
- * Revision 1.13  1995/10/06  14:38:06  adam
- * New result set method: r_score.
- * Local no (sysno) and score is transferred to retrieveCtrl.
- *
- * Revision 1.12  1995/09/28  09:52:11  adam
- * xfree/xmalloc used everywhere.
- *
- * Revision 1.11  1995/09/18  14:17:56  adam
- * Bug fixes.
- *
- * Revision 1.10  1995/09/15  14:45:39  adam
- * Bug fixes.
- *
- * Revision 1.9  1995/09/15  09:20:42  adam
- * Bug fixes.
- *
- * Revision 1.8  1995/09/08  14:52:42  adam
- * Work on relevance feedback.
- *
- * Revision 1.7  1995/09/07  13:58:44  adam
- * New parameter: result-set file descriptor (RSFD) to support multiple
- * positions within the same result-set.
- * Boolean operators: and, or, not implemented.
- *
- * Revision 1.6  1995/09/06  16:11:56  adam
- * More work on boolean sets.
- *
- * Revision 1.5  1995/09/05  16:36:59  adam
- * Minor changes.
- *
- * Revision 1.4  1995/09/05  11:43:24  adam
- * Complete version of temporary sets. Not tested yet though.
- *
- * Revision 1.3  1995/09/04  15:20:40  adam
- * More work on temp sets. is_open member removed.
- *
- * Revision 1.2  1995/09/04  09:10:56  adam
- * Minor changes.
- *
- * Revision 1.1  1994/11/04  13:21:30  quinn
- * Working.
- *
+ * $Id: rstemp.c,v 1.27 2002-02-20 17:30:01 adam Exp $
  */
 
 #include <fcntl.h>
@@ -215,8 +126,22 @@ static void r_flush (RSFD rfd, int mk)
 
     if (!info->fname && mk)
     {
-        char *s = (char*) tempnam (info->temp_path, "zrs");
+#if 1
+        char template[1024];
 
+        sprintf (template, "%s/zrsXXXXXX", info->temp_path);
+
+        info->fd = mkstemp (template);
+
+        if (info->fd == -1)
+        {
+            logf (LOG_FATAL|LOG_ERRNO, "mkstemp %s", template);
+            exit (1);
+        }
+        info->fname = (char *) xmalloc (strlen(template)+1);
+        strcpy (info->fname, template);
+#else
+        char *s = (char*) tempnam (info->temp_path, "zrs");
         info->fname = (char *) xmalloc (strlen(s)+1);
         strcpy (info->fname, s);
 
@@ -227,6 +152,7 @@ static void r_flush (RSFD rfd, int mk)
             logf (LOG_FATAL|LOG_ERRNO, "open %s", info->fname);
             exit (1);
         }
+#endif
     }
     if (info->fname && info->fd != -1 && info->dirty)
     {
index 5a75551..2a440d3 100644 (file)
@@ -1,2 +1,2 @@
 
-SUBDIRS=gils usmarc
+SUBDIRS=gils usmarc api
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
new file mode 100644 (file)
index 0000000..9d32563
--- /dev/null
@@ -0,0 +1,9 @@
+
+noinst_PROGRAMS = t1 t2
+
+t1_SOURCES = t1.c
+t2_SOURCES = t2.c
+
+CFLAGS = -I$(top_srcdir)/index $(YAZINC)
+
+LDADD = ../../index/libzebra.a $(YAZLIB) $(TCL_LIB)
diff --git a/test/api/t1.c b/test/api/t1.c
new file mode 100644 (file)
index 0000000..c276d4d
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id: t1.c,v 1.1 2002-02-20 17:30:02 adam Exp $
+ */
+
+#include <zebraapi.h>
+
+int main(int argc, char **argv)
+{
+    ZebraService zs;
+    ZebraHandle zh;
+
+    nmem_init();
+    zs = zebra_start("t1.cfg");
+    zh = zebra_open (zs);
+    
+    zebra_close (zh);
+    zebra_stop (zs);
+    nmem_exit ();
+    xmalloc_trav ("x");
+    exit (0);
+}
diff --git a/test/api/t1.cfg b/test/api/t1.cfg
new file mode 100644 (file)
index 0000000..815497d
--- /dev/null
@@ -0,0 +1,2 @@
+# $Id: t1.cfg,v 1.1 2002-02-20 17:30:02 adam Exp $
+profilepath: ../../../yaz/tab
\ No newline at end of file
diff --git a/test/api/t2.c b/test/api/t2.c
new file mode 100644 (file)
index 0000000..dfe8fef
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id: t2.c,v 1.1 2002-02-20 17:30:02 adam Exp $
+ */
+
+#include <zebraapi.h>
+
+int main(int argc, char **argv)
+{
+    ZebraService zs;
+    ZebraHandle zh;
+    const char *myrec =
+        "<gils>\n"
+        "  <title>My title</title>\n"
+        "</gils>\n";
+    ODR odr_input, odr_output;
+
+    nmem_init ();
+
+    odr_input = odr_createmem (ODR_DECODE);    
+    odr_output = odr_createmem (ODR_ENCODE);    
+    
+    zs = zebra_start("t2.cfg");
+    zh = zebra_open (zs);
+    
+    zebra_begin_trans (zh);
+    zebra_record_insert (zh, myrec, strlen(myrec));
+    zebra_end_trans (zh);
+    zebra_commit (zh);
+    zebra_close (zh);
+    zebra_stop (zs);
+
+    nmem_exit ();
+    xmalloc_trav ("x");
+    exit (0);
+}
diff --git a/test/api/t2.cfg b/test/api/t2.cfg
new file mode 100644 (file)
index 0000000..be03f44
--- /dev/null
@@ -0,0 +1,4 @@
+# $Id: t2.cfg,v 1.1 2002-02-20 17:30:02 adam Exp $
+profilepath: ../../../yaz/tab:../../tab
+
+attset: bib1.att
index 56c9752..5cc7812 100644 (file)
@@ -4,3 +4,7 @@ EXTRA_DIST = zebra.cfg test.sh
 dist-hook:
        -mkdir $(distdir)/records
        cp $(srcdir)/records/*.grs $(distdir)/records
+
+test:
+       ../../index/zmbolidx init
+       ../../index/zmbolidx update records
index 1666b8f..8428878 100644 (file)
@@ -1,5 +1,5 @@
 Name: zebra
-Version: 1.1
+Version: 1.1.1
 Release: 1
 Requires: yaz
 Copyright: Distributable
index ec3ae6d..61bd9ec 100644 (file)
@@ -1,5 +1,5 @@
 Name: zmbol
-Version: 1.1
+Version: 1.1.1
 Release: 1
 Requires: yaz
 Copyright: Commercial