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