Improved installation. Updated for inclusion of YAZ header files.
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /*
2  * Copyright (C) 1995-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zebraapi.c,v $
7  * Revision 1.26  1999-11-30 13:48:03  adam
8  * Improved installation. Updated for inclusion of YAZ header files.
9  *
10  * Revision 1.25  1999/11/04 15:00:45  adam
11  * Implemented delete result set(s).
12  *
13  * Revision 1.24  1999/10/14 14:33:50  adam
14  * Added truncation 5=106.
15  *
16  * Revision 1.23  1999/09/07 11:36:32  adam
17  * Minor changes.
18  *
19  * Revision 1.22  1999/08/02 10:13:47  adam
20  * Fixed bug regarding zebra_hits.
21  *
22  * Revision 1.21  1999/07/14 10:59:26  adam
23  * Changed functions isc_getmethod, isams_getmethod.
24  * Improved fatal error handling (such as missing EXPLAIN schema).
25  *
26  * Revision 1.20  1999/07/06 12:28:04  adam
27  * Updated record index structure. Format includes version ID. Compression
28  * algorithm ID is stored for each record block.
29  *
30  * Revision 1.19  1999/05/26 07:49:13  adam
31  * C++ compilation.
32  *
33  * Revision 1.18  1999/05/15 14:36:38  adam
34  * Updated dictionary. Implemented "compression" of dictionary.
35  *
36  * Revision 1.17  1999/05/12 13:08:06  adam
37  * First version of ISAMS.
38  *
39  * Revision 1.16  1999/02/19 10:38:30  adam
40  * Implemented chdir-setting.
41  *
42  * Revision 1.15  1999/02/17 12:18:12  adam
43  * Fixed zebra_close so that a NULL pointer is ignored.
44  *
45  * Revision 1.14  1999/02/02 14:51:11  adam
46  * Updated WIN32 code specific sections. Changed header.
47  *
48  * Revision 1.13  1998/12/16 12:23:30  adam
49  * Added facility for database name mapping using resource mapdb.
50  *
51  * Revision 1.12  1998/11/16 10:18:10  adam
52  * Better error reporting for result sets.
53  *
54  * Revision 1.11  1998/10/16 08:14:34  adam
55  * Updated record control system.
56  *
57  * Revision 1.10  1998/09/22 10:03:42  adam
58  * Changed result sets to be persistent in the sense that they can
59  * be re-searched if needed.
60  * Fixed memory leak in rsm_or.
61  *
62  * Revision 1.9  1998/09/02 13:53:17  adam
63  * Extra parameter decode added to search routines to implement
64  * persistent queries.
65  *
66  * Revision 1.8  1998/08/24 17:29:23  adam
67  * Minor changes.
68  *
69  * Revision 1.7  1998/06/24 12:16:13  adam
70  * Support for relations on text operands. Open range support in
71  * DFA module (i.e. [-j], [g-]).
72  *
73  * Revision 1.6  1998/06/22 11:36:47  adam
74  * Added authentication check facility to zebra.
75  *
76  * Revision 1.5  1998/06/13 00:14:08  adam
77  * Minor changes.
78  *
79  * Revision 1.4  1998/06/12 12:22:12  adam
80  * Work on Zebra API.
81  *
82  * Revision 1.3  1998/05/27 16:57:44  adam
83  * Zebra returns surrogate diagnostic for single records when
84  * appropriate.
85  *
86  * Revision 1.2  1998/05/20 10:12:19  adam
87  * Implemented automatic EXPLAIN database maintenance.
88  * Modified Zebra to work with ASN.1 compiled version of YAZ.
89  *
90  * Revision 1.1  1998/03/05 08:45:13  adam
91  * New result set model and modular ranking system. Moved towards
92  * descent server API. System information stored as "SGML" records.
93  *
94  */
95
96 #include <stdio.h>
97 #ifdef WIN32
98 #include <io.h>
99 #include <process.h>
100 #include <direct.h>
101 #else
102 #include <unistd.h>
103 #endif
104
105 #include <yaz/diagbib1.h>
106 #include "zserver.h"
107
108 static void zebra_chdir (ZebraHandle zh)
109 {
110     const char *dir = res_get (zh->res, "chdir");
111     if (!dir)
112         return;
113     logf (LOG_DEBUG, "chdir %s", dir);
114 #ifdef WIN32
115     _chdir(dir);
116 #else
117     chdir (dir);
118 #endif
119 }
120
121 static void zebra_register_unlock (ZebraHandle zh);
122
123 static int zebra_register_lock (ZebraHandle zh)
124 {
125     time_t lastChange;
126     int state;
127
128     zh->errCode = 0;
129     zh->errString = 0;
130
131     zebra_chdir (zh);
132
133     state = zebra_server_lock_get_state(zh, &lastChange);
134
135     switch (state)
136     {
137     case 'c':
138         state = 1;
139         break;
140     default:
141         state = 0;
142     }
143     zebra_server_lock (zh, state);
144 #if HAVE_SYS_TIMES_H
145     times (&zh->tms1);
146 #endif
147     if (zh->registerState == state)
148     {
149         if (zh->registerChange >= lastChange)
150             return 0;
151         logf (LOG_LOG, "Register completely updated since last access");
152     }
153     else if (zh->registerState == -1)
154         logf (LOG_LOG, "Reading register using state %d pid=%ld", state,
155               (long) getpid());
156     else
157         logf (LOG_LOG, "Register has changed state from %d to %d",
158               zh->registerState, state);
159     zh->registerChange = lastChange;
160     if (zh->records)
161     {
162         zebraExplain_close (zh->zei, 0, 0);
163         if (zh->dict)
164             dict_close (zh->dict);
165         if (zh->sortIdx)
166             sortIdx_close (zh->sortIdx);
167         if (zh->isams)
168             isams_close (zh->isams);
169 #if ZMBOL
170         if (zh->isam)
171             is_close (zh->isam);
172         if (zh->isamc)
173             isc_close (zh->isamc);
174 #endif
175         rec_close (&zh->records);
176     }
177     bf_cache (zh->bfs, state ? res_get (zh->res, "shadow") : NULL);
178     zh->registerState = state;
179
180     zh->isams = NULL;
181 #if ZMBOL
182     zh->isam = NULL;
183     zh->isamc = NULL;
184 #endif
185     zh->dict = NULL;
186     zh->sortIdx = NULL;
187     zh->zei = NULL;
188
189     if (!(zh->records = rec_open (zh->bfs, 0, 0)))
190     {
191         logf (LOG_WARN, "rec_open");
192         zh->errCode = 2;
193     }
194     else
195     {
196         if (!(zh->dict = dict_open (zh->bfs, FNAME_DICT, 40, 0, 0)))
197         {
198             logf (LOG_WARN, "dict_open");
199             zh->errCode = 2;
200         }
201         if (!(zh->sortIdx = sortIdx_open (zh->bfs, 0)))
202         {
203             logf (LOG_WARN, "sortIdx_open");
204             zh->errCode = 2;
205         }
206         if (res_get_match (zh->res, "isam", "s", ISAM_DEFAULT))
207         {
208             struct ISAMS_M_s isams_m;
209             if (!(zh->isams = isams_open (zh->bfs, FNAME_ISAMS, 0,
210                                           key_isams_m(zh->res, &isams_m))))
211             {
212                 logf (LOG_WARN, "isams_open");
213                 zh->errCode = 2;
214             }
215         }
216 #if ZMBOL
217         else if (res_get_match (zh->res, "isam", "i", ISAM_DEFAULT))
218         {
219             if (!(zh->isam = is_open (zh->bfs, FNAME_ISAM, key_compare, 0,
220                                       sizeof (struct it_key), zh->res)))
221             {
222                 logf (LOG_WARN, "is_open");
223                 zh->errCode = 2;
224             }
225         }
226         else if (res_get_match (zh->res, "isam", "c", ISAM_DEFAULT))
227         {
228             struct ISAMC_M_s isamc_m;
229             if (!(zh->isamc = isc_open (zh->bfs, FNAME_ISAMC,
230                                         0, key_isamc_m(zh->res, &isamc_m))))
231             {
232                 logf (LOG_WARN, "isc_open");
233                 zh->errCode = 2;
234             }
235         }
236 #endif
237         zh->zei = zebraExplain_open (zh->records, zh->dh, zh->res, 0, 0, 0);
238         if (!zh->zei)
239         {
240             logf (LOG_WARN, "Cannot obtain EXPLAIN information");
241             zh->errCode = 2;
242         }
243     }
244     if (zh->errCode)
245     {
246         zebra_register_unlock (zh);
247         zh->registerState = -1;
248         return -1;
249     }
250     return 0;
251 }
252
253 static void zebra_register_unlock (ZebraHandle zh)
254 {
255     static int waitSec = -1;
256
257 #if HAVE_SYS_TIMES_H
258     times (&zh->tms2);
259     logf (LOG_LOG, "user/system: %ld/%ld",
260                         (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
261                         (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
262 #endif
263     if (waitSec == -1)
264     {
265         char *s = res_get (zh->res, "debugRequestWait");
266         if (s)
267             waitSec = atoi (s);
268         else
269             waitSec = 0;
270     }
271 #ifdef WIN32
272 #else
273     if (waitSec > 0)
274         sleep (waitSec);
275 #endif
276     if (zh->registerState != -1)
277         zebra_server_unlock (zh, zh->registerState);
278 }
279
280 ZebraHandle zebra_open (const char *configName)
281 {
282     ZebraHandle zh;
283
284     zh = (ZebraHandle) xmalloc (sizeof(*zh));
285     if (!(zh->res = res_open (configName)))
286     {
287         logf (LOG_WARN, "Failed to read resources `%s'", configName);
288         return NULL;
289     }
290     zebra_chdir (zh);
291     zebra_server_lock_init (zh);
292     zh->dh = data1_create ();
293     if (!zh->dh)
294     {
295         zebra_server_lock_destroy (zh);
296         xfree (zh);
297         return 0;
298     }
299     zh->bfs = bfs_create (res_get (zh->res, "register"));
300     if (!zh->bfs)
301     {
302         zebra_server_lock_destroy (zh);
303         data1_destroy(zh->dh);
304         xfree (zh);
305         return 0;
306     }
307     bf_lockDir (zh->bfs, res_get (zh->res, "lockDir"));
308     data1_set_tabpath (zh->dh, res_get(zh->res, "profilePath"));
309     zh->sets = NULL;
310     zh->registerState = -1;  /* trigger open of registers! */
311     zh->registerChange = 0;
312     zh->recTypes = recTypes_init (zh->dh);
313     recTypes_default_handlers (zh->recTypes);
314
315     zh->records = NULL;
316     zh->zebra_maps = zebra_maps_open (zh->res);
317     zh->rank_classes = NULL;
318     zh->errCode = 0;
319     zh->errString = 0;
320     
321     zebraRankInstall (zh, rank1_class);
322
323     if (!res_get (zh->res, "passwd"))
324         zh->passwd_db = NULL;
325     else
326     {
327         zh->passwd_db = passwd_db_open ();
328         if (!zh->passwd_db)
329             logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
330         else
331             passwd_db_file (zh->passwd_db, res_get (zh->res, "passwd"));
332     }
333     return zh;
334 }
335
336 void zebra_close (ZebraHandle zh)
337 {
338     if (!zh)
339         return;
340     zebra_chdir (zh);
341     if (zh->records)
342     {
343         resultSetDestroy (zh, -1, 0, 0);
344         zebraExplain_close (zh->zei, 0, 0);
345         dict_close (zh->dict);
346         sortIdx_close (zh->sortIdx);
347         if (zh->isams)
348             isams_close (zh->isams);
349 #if ZMBOL
350         if (zh->isam)
351             is_close (zh->isam);
352         if (zh->isamc)
353             isc_close (zh->isamc);
354 #endif
355         rec_close (&zh->records);
356         zebra_register_unlock (zh);
357     }
358     recTypes_destroy (zh->recTypes);
359     zebra_maps_close (zh->zebra_maps);
360     zebraRankDestroy (zh);
361     bfs_destroy (zh->bfs);
362     data1_destroy (zh->dh);
363     zebra_server_lock_destroy (zh);
364
365     if (zh->passwd_db)
366         passwd_db_close (zh->passwd_db);
367     res_close (zh->res);
368     xfree (zh);
369 }
370
371 struct map_baseinfo {
372     ZebraHandle zh;
373     NMEM mem;
374     int num_bases;
375     char **basenames;
376     int new_num_bases;
377     char **new_basenames;
378     int new_num_max;
379 };
380         
381 void map_basenames_func (void *vp, const char *name, const char *value)
382 {
383     struct map_baseinfo *p = (struct map_baseinfo *) vp;
384     int i, no;
385     char fromdb[128], todb[8][128];
386     
387     no =
388         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
389                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
390                 todb[5], todb[6], todb[7]);
391     if (no < 2)
392         return ;
393     no--;
394     for (i = 0; i<p->num_bases; i++)
395         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
396         {
397             p->basenames[i] = 0;
398             for (i = 0; i < no; i++)
399             {
400                 if (p->new_num_bases == p->new_num_max)
401                     return;
402                 p->new_basenames[(p->new_num_bases)++] = 
403                     nmem_strdup (p->mem, todb[i]);
404             }
405             return;
406         }
407 }
408
409 void map_basenames (ZebraHandle zh, ODR stream,
410                     int *num_bases, char ***basenames)
411 {
412     struct map_baseinfo info;
413     struct map_baseinfo *p = &info;
414     int i;
415
416     info.zh = zh;
417     info.num_bases = *num_bases;
418     info.basenames = *basenames;
419     info.new_num_max = 128;
420     info.new_num_bases = 0;
421     info.new_basenames = (char **)
422         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
423     info.mem = stream->mem;
424
425     res_trav (zh->res, "mapdb", &info, map_basenames_func);
426     
427     for (i = 0; i<p->num_bases; i++)
428         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
429         {
430             p->new_basenames[(p->new_num_bases)++] = 
431                 nmem_strdup (p->mem, p->basenames[i]);
432         }
433     *num_bases = info.new_num_bases;
434     *basenames = info.new_basenames;
435     for (i = 0; i<*num_bases; i++)
436         logf (LOG_LOG, "base %s", (*basenames)[i]);
437 }
438
439 void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
440                        Z_RPNQuery *query, int num_bases, char **basenames, 
441                        const char *setname)
442 {
443     zh->hits = 0;
444     if (zebra_register_lock (zh))
445         return;
446     map_basenames (zh, stream, &num_bases, &basenames);
447     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
448
449     zebra_register_unlock (zh);
450 }
451
452 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
453                              const char *setname, Z_RecordComposition *comp,
454                              oid_value input_format, int num_recs,
455                              ZebraRetrievalRecord *recs)
456 {
457     ZebraPosSet poset;
458     int i, *pos_array;
459
460     if (zebra_register_lock (zh))
461         return;
462     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
463     for (i = 0; i<num_recs; i++)
464         pos_array[i] = recs[i].position;
465     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
466     if (!poset)
467     {
468         logf (LOG_DEBUG, "zebraPosSetCreate error");
469         zh->errCode = 30;
470         zh->errString = nmem_strdup (stream->mem, setname);
471     }
472     else
473     {
474         for (i = 0; i<num_recs; i++)
475         {
476             if (!poset[i].sysno)
477             {
478                 char num_str[20];
479
480                 sprintf (num_str, "%d", pos_array[i]);  
481                 zh->errCode = 13;
482                 zh->errString = nmem_strdup (stream->mem, num_str);
483                 break;
484             }
485             else
486             {
487                 recs[i].errCode =
488                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
489                                         stream, input_format, comp,
490                                         &recs[i].format, &recs[i].buf,
491                                         &recs[i].len,
492                                         &recs[i].base);
493                 recs[i].errString = NULL;
494             }
495         }
496         zebraPosSetDestroy (zh, poset, num_recs);
497     }
498     zebra_register_unlock (zh);
499     xfree (pos_array);
500 }
501
502 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
503                  oid_value attributeset,
504                  int num_bases, char **basenames,
505                  int *position, int *num_entries, ZebraScanEntry **entries,
506                  int *is_partial)
507 {
508     if (zebra_register_lock (zh))
509     {
510         *entries = 0;
511         *num_entries = 0;
512         return;
513     }
514     map_basenames (zh, stream, &num_bases, &basenames);
515     rpn_scan (zh, stream, zapt, attributeset,
516               num_bases, basenames, position,
517               num_entries, entries, is_partial);
518     zebra_register_unlock (zh);
519 }
520
521 void zebra_sort (ZebraHandle zh, ODR stream,
522                  int num_input_setnames, const char **input_setnames,
523                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
524                  int *sort_status)
525 {
526     if (zebra_register_lock (zh))
527         return;
528     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
529                    output_setname, sort_sequence, sort_status);
530     zebra_register_unlock (zh);
531 }
532
533 int zebra_deleleResultSet(ZebraHandle zh, int function,
534                           int num_setnames, char **setnames,
535                           int *statuses)
536 {
537     int i, status;
538     if (zebra_register_lock (zh))
539         return Z_DeleteStatus_systemProblemAtTarget;
540     switch (function)
541     {
542     case Z_DeleteRequest_list:
543         resultSetDestroy (zh, num_setnames, setnames, statuses);
544         break;
545     case Z_DeleteRequest_all:
546         resultSetDestroy (zh, -1, 0, statuses);
547         break;
548     }
549     zebra_register_unlock (zh);
550     status = Z_DeleteStatus_success;
551     for (i = 0; i<num_setnames; i++)
552         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
553             status = statuses[i];
554     return status;
555 }
556
557 int zebra_errCode (ZebraHandle zh)
558 {
559     return zh->errCode;
560 }
561
562 const char *zebra_errString (ZebraHandle zh)
563 {
564     return diagbib1_str (zh->errCode);
565 }
566
567 char *zebra_errAdd (ZebraHandle zh)
568 {
569     return zh->errString;
570 }
571
572 int zebra_hits (ZebraHandle zh)
573 {
574     return zh->hits;
575 }
576
577 int zebra_auth (ZebraHandle zh, const char *user, const char *pass)
578 {
579     if (!zh->passwd_db || !passwd_db_auth (zh->passwd_db, user, pass))
580         return 0;
581     return 1;
582 }
583
584 void zebra_setDB (ZebraHandle zh, int num_bases, char **basenames)
585 {
586
587 }
588
589 void zebra_setRecordType (ZebraHandle zh, const char *type)
590 {
591
592 }
593
594 void zebra_setGroup (ZebraHandle zh, const char *group)
595 {
596
597 }
598
599 void zebra_admin (ZebraHandle zh, const char *command)
600 {
601
602 }