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