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