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