093b9500e904860b6ffbd6d7744ebafa76ce73c3
[idzebra-moved-to-github.git] / index / zebraapi.c
1 /*
2  * Copyright (C) 1995-2002, Index Data
3  * All rights reserved.
4  *
5  * $Id: zebraapi.c,v 1.64 2002-07-29 20:04:24 adam Exp $
6  */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #ifdef WIN32
11 #include <io.h>
12 #include <process.h>
13 #include <direct.h>
14 #else
15 #include <unistd.h>
16 #endif
17
18 #include <yaz/diagbib1.h>
19 #include "index.h"
20 #include <charmap.h>
21
22 static Res zebra_open_res (ZebraHandle zh);
23 static void zebra_close_res (ZebraHandle zh);
24
25 static void zebra_chdir (ZebraService zh)
26 {
27     const char *dir = res_get (zh->global_res, "chdir");
28     if (!dir)
29         return;
30     logf (LOG_DEBUG, "chdir %s", dir);
31 #ifdef WIN32
32     _chdir(dir);
33 #else
34     chdir (dir);
35 #endif
36 }
37
38 static void zebra_flush_reg (ZebraHandle zh)
39 {
40     zebraExplain_flush (zh->reg->zei, zh);
41     
42     extract_flushWriteKeys (zh);
43     zebra_index_merge (zh);
44 }
45
46 static struct zebra_register *zebra_register_open (ZebraService zs, 
47                                                    const char *name,
48                                                    int rw, int useshadow,
49                                                    Res res,
50                                                    const char *reg_path);
51 static void zebra_register_close (ZebraService zs, struct zebra_register *reg);
52
53 ZebraHandle zebra_open (ZebraService zs)
54 {
55     ZebraHandle zh;
56     const char *default_encoding;
57
58     if (!zs)
59         return 0;
60
61     zh = (ZebraHandle) xmalloc (sizeof(*zh));
62     yaz_log (LOG_LOG, "zebra_open zs=%p returns %p", zs, zh);
63
64     zh->service = zs;
65     zh->reg = 0;          /* no register attached yet */
66     zh->sets = 0;
67     zh->destroyed = 0;
68     zh->errCode = 0;
69     zh->errString = 0;
70     zh->res = 0;
71
72     zh->reg_name = xstrdup ("");
73     zh->path_reg = 0;
74     zh->num_basenames = 0;
75     zh->basenames = 0;
76
77     zh->trans_no = 0;
78
79     zh->lock_normal = 0;
80     zh->lock_shadow = 0;
81
82     zh->admin_databaseName = 0;
83
84     zh->shadow_enable = 1;
85
86     default_encoding = res_get_def(zs->global_res, "encoding", "ISO-8859-1");
87     zh->record_encoding = xstrdup (default_encoding);
88 #if HAVE_ICONV_H
89     zh->iconv_to_utf8 =
90         iconv_open ("UTF-8", default_encoding);
91     if (zh->iconv_to_utf8 == (iconv_t)(-1))
92         yaz_log (LOG_WARN, "iconv: %s to UTF-8 unsupported",
93            default_encoding);
94     zh->iconv_from_utf8 =
95         iconv_open (default_encoding, "UTF-8");
96     if (zh->iconv_to_utf8 == (iconv_t)(-1))
97         yaz_log (LOG_WARN, "iconv: UTF-8 to %s unsupported",
98            default_encoding);
99 #endif
100
101     zebra_mutex_cond_lock (&zs->session_lock);
102
103     zh->next = zs->sessions;
104     zs->sessions = zh;
105
106     zebra_mutex_cond_unlock (&zs->session_lock);
107
108     return zh;
109 }
110
111 ZebraService zebra_start (const char *configName)
112 {
113     Res res;
114
115     yaz_log (LOG_LOG, "zebra_start %s", configName);
116
117     if (!(res = res_open (configName, 0)))
118         yaz_log (LOG_WARN, "Cannot read resources `%s'", configName);
119     else
120     {
121         ZebraService zh = xmalloc (sizeof(*zh));
122
123         yaz_log (LOG_LOG, "Read resources `%s'", configName);
124         
125         zh->global_res = res;
126         zh->configName = xstrdup(configName);
127         zh->sessions = 0;
128         
129         zebra_chdir (zh);
130         
131         zebra_mutex_cond_init (&zh->session_lock);
132         if (!res_get (zh->global_res, "passwd"))
133             zh->passwd_db = NULL;
134         else
135         {
136             zh->passwd_db = passwd_db_open ();
137             if (!zh->passwd_db)
138                 logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
139             else
140                 passwd_db_file (zh->passwd_db,
141                                 res_get (zh->global_res, "passwd"));
142         }
143         zh->path_root = res_get (zh->global_res, "root");
144         return zh;
145     }
146     return 0;
147 }
148
149 static
150 struct zebra_register *zebra_register_open (ZebraService zs, const char *name,
151                                             int rw, int useshadow, Res res,
152                                             const char *reg_path)
153 {
154     struct zebra_register *reg;
155     int record_compression = REC_COMPRESS_NONE;
156     char *recordCompression = 0;
157
158     reg = xmalloc (sizeof(*reg));
159
160     assert (name);
161     reg->name = xstrdup (name);
162
163     reg->seqno = 0;
164     reg->last_val = 0;
165
166     assert (res);
167
168     yaz_log (LOG_LOG, "zebra_register_open rw = %d useshadow=%d p=%p",
169              rw, useshadow, reg);
170
171     reg->dh = data1_createx (DATA1_FLAG_XML);
172     if (!reg->dh)
173         return 0;
174     reg->bfs = bfs_create (res_get (res, "register"), reg_path);
175     if (!reg->bfs)
176     {
177         data1_destroy(reg->dh);
178         return 0;
179     }
180     if (useshadow)
181         bf_cache (reg->bfs, res_get (res, "shadow"));
182     data1_set_tabpath (reg->dh, res_get(res, "profilePath"));
183     data1_set_tabroot (reg->dh, reg_path);
184     reg->recTypes = recTypes_init (reg->dh);
185     recTypes_default_handlers (reg->recTypes);
186
187     reg->zebra_maps = zebra_maps_open (res, reg_path);
188     reg->rank_classes = NULL;
189
190     reg->key_buf = 0;
191
192     reg->keys.buf_max = 0;
193     reg->keys.buf = 0;
194
195     reg->records = 0;
196     reg->dict = 0;
197     reg->sortIdx = 0;
198     reg->isams = 0;
199     reg->matchDict = 0;
200     reg->isam = 0;
201     reg->isamc = 0;
202     reg->isamd = 0;
203     reg->isamb = 0;
204     reg->zei = 0;
205     reg->matchDict = 0;
206     
207     zebraRankInstall (reg, rank1_class);
208
209     recordCompression = res_get_def (res, "recordCompression", "none");
210     if (!strcmp (recordCompression, "none"))
211         record_compression = REC_COMPRESS_NONE;
212     if (!strcmp (recordCompression, "bzip2"))
213         record_compression = REC_COMPRESS_BZIP2;
214
215     if (!(reg->records = rec_open (reg->bfs, rw, record_compression)))
216     {
217         logf (LOG_WARN, "rec_open");
218         return 0;
219     }
220     if (rw)
221     {
222         reg->matchDict = dict_open (reg->bfs, GMATCH_DICT, 20, 1, 0);
223     }
224     if (!(reg->dict = dict_open (reg->bfs, FNAME_DICT, 40, rw, 0)))
225     {
226         logf (LOG_WARN, "dict_open");
227         return 0;
228     }
229     if (!(reg->sortIdx = sortIdx_open (reg->bfs, rw)))
230     {
231         logf (LOG_WARN, "sortIdx_open");
232         return 0;
233     }
234     if (res_get_match (res, "isam", "s", ISAM_DEFAULT))
235     {
236         struct ISAMS_M_s isams_m;
237         if (!(reg->isams = isams_open (reg->bfs, FNAME_ISAMS, rw,
238                                       key_isams_m(res, &isams_m))))
239         {
240             logf (LOG_WARN, "isams_open");
241             return 0;
242         }
243     }
244     if (res_get_match (res, "isam", "i", ISAM_DEFAULT))
245     {
246         if (!(reg->isam = is_open (reg->bfs, FNAME_ISAM, key_compare, rw,
247                                   sizeof (struct it_key), res)))
248         {
249             logf (LOG_WARN, "is_open");
250             return 0;
251         }
252     }
253     if (res_get_match (res, "isam", "c", ISAM_DEFAULT))
254     {
255         struct ISAMC_M_s isamc_m;
256         if (!(reg->isamc = isc_open (reg->bfs, FNAME_ISAMC,
257                                     rw, key_isamc_m(res, &isamc_m))))
258         {
259             logf (LOG_WARN, "isc_open");
260             return 0;
261         }
262     }
263     if (res_get_match (res, "isam", "d", ISAM_DEFAULT))
264     {
265         struct ISAMD_M_s isamd_m;
266         
267         if (!(reg->isamd = isamd_open (reg->bfs, FNAME_ISAMD,
268                                       rw, key_isamd_m(res, &isamd_m))))
269         {
270             logf (LOG_WARN, "isamd_open");
271             return 0;
272         }
273     }
274     if (res_get_match (res, "isam", "b", ISAM_DEFAULT))
275     {
276         struct ISAMC_M_s isamc_m;
277         
278         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
279                                        rw, key_isamc_m(res, &isamc_m), 0)))
280         {
281             logf (LOG_WARN, "isamb_open");
282             return 0;
283         }
284     }
285     if (res_get_match (res, "isam", "bc", ISAM_DEFAULT))
286     {
287         struct ISAMC_M_s isamc_m;
288         
289         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
290                                        rw, key_isamc_m(res, &isamc_m), 1)))
291         {
292             logf (LOG_WARN, "isamb_open");
293             return 0;
294         }
295     }
296     if (res_get_match (res, "isam", "null", ISAM_DEFAULT))
297     {
298         struct ISAMC_M_s isamc_m;
299         
300         if (!(reg->isamb = isamb_open (reg->bfs, "isamb",
301                                        rw, key_isamc_m(res, &isamc_m), -1)))
302         {
303             logf (LOG_WARN, "isamb_open");
304             return 0;
305         }
306     }
307     reg->zei = zebraExplain_open (reg->records, reg->dh,
308                                   res, rw, reg,
309                                   explain_extract);
310     if (!reg->zei)
311     {
312         logf (LOG_WARN, "Cannot obtain EXPLAIN information");
313         return 0;
314     }
315     reg->active = 2;
316     yaz_log (LOG_LOG, "zebra_register_open ok p=%p", reg);
317     return reg;
318 }
319
320 void zebra_admin_shutdown (ZebraHandle zh)
321 {
322     zebra_mutex_cond_lock (&zh->service->session_lock);
323     zh->service->stop_flag = 1;
324     zebra_mutex_cond_unlock (&zh->service->session_lock);
325 }
326
327 void zebra_admin_start (ZebraHandle zh)
328 {
329     ZebraService zs = zh->service;
330     zh->errCode = 0;
331     zebra_mutex_cond_lock (&zs->session_lock);
332     zebra_mutex_cond_unlock (&zs->session_lock);
333 }
334
335 static void zebra_register_close (ZebraService zs, struct zebra_register *reg)
336 {
337     yaz_log(LOG_LOG, "zebra_register_close p=%p", reg);
338     reg->stop_flag = 0;
339     zebra_chdir (zs);
340     if (reg->records)
341     {
342         zebraExplain_close (reg->zei);
343         dict_close (reg->dict);
344         if (reg->matchDict)
345             dict_close (reg->matchDict);
346         sortIdx_close (reg->sortIdx);
347         if (reg->isams)
348             isams_close (reg->isams);
349         if (reg->isam)
350             is_close (reg->isam);
351         if (reg->isamc)
352             isc_close (reg->isamc);
353         if (reg->isamd)
354             isamd_close (reg->isamd);
355         if (reg->isamb)
356             isamb_close (reg->isamb);
357         rec_close (&reg->records);
358     }
359
360     recTypes_destroy (reg->recTypes);
361     zebra_maps_close (reg->zebra_maps);
362     zebraRankDestroy (reg);
363     bfs_destroy (reg->bfs);
364     data1_destroy (reg->dh);
365
366     xfree (reg->key_buf);
367     xfree (reg->name);
368     xfree (reg);
369     yaz_log (LOG_LOG, "zebra_register_close 2");
370 }
371
372 void zebra_stop(ZebraService zs)
373 {
374     if (!zs)
375         return ;
376     yaz_log (LOG_LOG, "zebra_stop");
377
378     zebra_mutex_cond_lock (&zs->session_lock);
379     while (zs->sessions)
380     {
381         zebra_close (zs->sessions);
382     }
383         
384     zebra_mutex_cond_unlock (&zs->session_lock);
385
386     zebra_mutex_cond_destroy (&zs->session_lock);
387
388     if (zs->passwd_db)
389         passwd_db_close (zs->passwd_db);
390
391     res_close (zs->global_res);
392     xfree (zs->configName);
393     xfree (zs->path_root);
394     xfree (zs);
395 }
396
397 void zebra_close (ZebraHandle zh)
398 {
399     ZebraService zs;
400     struct zebra_session **sp;
401
402     if (!zh)
403         return;
404
405     zs = zh->service;
406     yaz_log (LOG_LOG, "zebra_close zh=%p", zh);
407     if (!zh)
408         return ;
409     resultSetDestroy (zh, -1, 0, 0);
410
411
412     if (zh->reg)
413         zebra_register_close (zh->service, zh->reg);
414     zebra_close_res (zh);
415
416     xfree (zh->record_encoding);
417 #if HAVE_ICONV_H
418     if (zh->iconv_to_utf8 != (iconv_t) (-1))
419         iconv_close (zh->iconv_to_utf8);
420     if (zh->iconv_from_utf8 != (iconv_t) (-1))
421         iconv_close (zh->iconv_from_utf8);
422 #endif
423
424     xfree (zh->admin_databaseName);
425     zebra_mutex_cond_lock (&zs->session_lock);
426     zebra_lock_destroy (zh->lock_normal);
427     zebra_lock_destroy (zh->lock_shadow);
428     sp = &zs->sessions;
429     while (1)
430     {
431         assert (*sp);
432         if (*sp == zh)
433         {
434             *sp = (*sp)->next;
435             break;
436         }
437         sp = &(*sp)->next;
438     }
439 //    if (!zs->sessions && zs->stop_flag)
440 //      zebra_register_deactivate(zs);
441     zebra_mutex_cond_unlock (&zs->session_lock);
442     xfree (zh->reg_name);
443     xfree (zh);
444 }
445
446 struct map_baseinfo {
447     ZebraHandle zh;
448     NMEM mem;
449     int num_bases;
450     char **basenames;
451     int new_num_bases;
452     char **new_basenames;
453     int new_num_max;
454 };
455
456 static Res zebra_open_res (ZebraHandle zh)
457 {
458     Res res = 0;
459     char fname[512];
460     if (zh->path_reg)
461     {
462         sprintf (fname, "%.200s/zebra.cfg", zh->path_reg);
463         res = res_open (fname, zh->service->global_res);
464         if (!res)
465             res = zh->service->global_res;
466     }
467     else if (*zh->reg_name == 0)
468     {
469         res = zh->service->global_res;
470     }
471     else
472     {
473         yaz_log (LOG_WARN, "no register root specified");
474         return 0;  /* no path for register - fail! */
475     }
476     return res;
477 }
478
479 static void zebra_close_res (ZebraHandle zh)
480 {
481     if (zh->res != zh->service->global_res)
482         res_close (zh->res);
483     zh->res = 0;
484 }
485
486 static int zebra_select_register (ZebraHandle zh, const char *new_reg)
487 {
488     if (zh->res && strcmp (zh->reg_name, new_reg) == 0)
489         return 0;
490     if (!zh->res)
491     {
492         assert (zh->reg == 0);
493         assert (*zh->reg_name == 0);
494     }
495     else
496     {
497         if (zh->reg)
498         {
499             resultSetInvalidate (zh);
500             zebra_register_close (zh->service, zh->reg);
501             zh->reg = 0;
502         }
503         zebra_close_res(zh);
504     }
505     xfree (zh->reg_name);
506     zh->reg_name = xstrdup (new_reg);
507
508     xfree (zh->path_reg);
509     zh->path_reg = 0;
510     if (zh->service->path_root)
511     {
512         zh->path_reg = xmalloc (strlen(zh->service->path_root) + 
513                                 strlen(zh->reg_name) + 3);
514         strcpy (zh->path_reg, zh->service->path_root);
515         if (*zh->reg_name)
516         {
517             strcat (zh->path_reg, "/");
518             strcat (zh->path_reg, zh->reg_name);
519         }
520     }
521     zh->res = zebra_open_res (zh);
522     
523     if (zh->lock_normal)
524         zebra_lock_destroy (zh->lock_normal);
525     zh->lock_normal = 0;
526
527     if (zh->lock_shadow)
528         zebra_lock_destroy (zh->lock_shadow);
529     zh->lock_shadow = 0;
530
531     if (zh->res)
532     {
533         char fname[512];
534         const char *lock_area  =res_get (zh->res, "lockDir");
535         
536         if (!lock_area && zh->path_reg)
537             res_put (zh->res, "lockDir", zh->path_reg);
538         sprintf (fname, "norm.%s.LCK", zh->reg_name);
539         zh->lock_normal =
540             zebra_lock_create (res_get(zh->res, "lockDir"), fname, 0);
541         
542         sprintf (fname, "shadow.%s.LCK", zh->reg_name);
543         zh->lock_shadow =
544             zebra_lock_create (res_get(zh->res, "lockDir"), fname, 0);
545
546     }
547     return 1;
548 }
549
550 void map_basenames_func (void *vp, const char *name, const char *value)
551 {
552     struct map_baseinfo *p = (struct map_baseinfo *) vp;
553     int i, no;
554     char fromdb[128], todb[8][128];
555     
556     no =
557         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
558                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
559                 todb[5], todb[6], todb[7]);
560     if (no < 2)
561         return ;
562     no--;
563     for (i = 0; i<p->num_bases; i++)
564         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
565         {
566             p->basenames[i] = 0;
567             for (i = 0; i < no; i++)
568             {
569                 if (p->new_num_bases == p->new_num_max)
570                     return;
571                 p->new_basenames[(p->new_num_bases)++] = 
572                     nmem_strdup (p->mem, todb[i]);
573             }
574             return;
575         }
576 }
577
578 void map_basenames (ZebraHandle zh, ODR stream,
579                     int *num_bases, char ***basenames)
580 {
581     struct map_baseinfo info;
582     struct map_baseinfo *p = &info;
583     int i;
584
585     info.zh = zh;
586     info.num_bases = *num_bases;
587     info.basenames = *basenames;
588     info.new_num_max = 128;
589     info.new_num_bases = 0;
590     info.new_basenames = (char **)
591         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
592     info.mem = stream->mem;
593
594     res_trav (zh->service->global_res, "mapdb", &info, map_basenames_func);
595     
596     for (i = 0; i<p->num_bases; i++)
597         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
598         {
599             p->new_basenames[(p->new_num_bases)++] = 
600                 nmem_strdup (p->mem, p->basenames[i]);
601         }
602     *num_bases = info.new_num_bases;
603     *basenames = info.new_basenames;
604     for (i = 0; i<*num_bases; i++)
605         logf (LOG_LOG, "base %s", (*basenames)[i]);
606 }
607
608 int zebra_select_database (ZebraHandle zh, const char *basename)
609 {
610     return zebra_select_databases (zh, 1, &basename);
611 }
612
613 int zebra_select_databases (ZebraHandle zh, int num_bases,
614                             const char **basenames)
615 {
616     int i;
617     const char *cp;
618     int len = 0;
619     char *new_reg = 0;
620     
621     if (num_bases < 1)
622     {
623         zh->errCode = 23;
624         return -1;
625     }
626     for (i = 0; i < zh->num_basenames; i++)
627         xfree (zh->basenames[i]);
628     xfree (zh->basenames);
629     
630     zh->num_basenames = num_bases;
631     zh->basenames = xmalloc (zh->num_basenames * sizeof(*zh->basenames));
632     for (i = 0; i < zh->num_basenames; i++)
633         zh->basenames[i] = xstrdup (basenames[i]);
634
635     cp = strrchr(basenames[0], '/');
636     if (cp)
637     {
638         len = cp - basenames[0];
639         new_reg = xmalloc (len + 1);
640         memcpy (new_reg, basenames[0], len);
641         new_reg[len] = '\0';
642     }
643     else
644         new_reg = xstrdup ("");
645     for (i = 1; i<num_bases; i++)
646     {
647         const char *cp1;
648
649         cp1 = strrchr (basenames[i], '/');
650         if (cp)
651         {
652             if (!cp1)
653             {
654                 zh->errCode = 23;
655                 return -1;
656             }
657             if (len != cp1 - basenames[i] ||
658                 memcmp (basenames[i], new_reg, len))
659             {
660                 zh->errCode = 23;
661                 return -1;
662             }
663         }
664         else
665         {
666             if (cp1)
667             {
668                 zh->errCode = 23;
669                 return -1;
670             }
671         }
672     }
673     zebra_select_register (zh, new_reg);
674     xfree (new_reg);
675     if (!zh->res)
676     {
677         zh->errCode = 109;
678         return -1;
679     }
680     return 0;
681 }
682
683 void zebra_search_rpn (ZebraHandle zh, ODR decode, ODR stream,
684                        Z_RPNQuery *query, const char *setname, int *hits)
685 {
686     zh->hits = 0;
687     *hits = 0;
688
689     if (zebra_begin_read (zh))
690         return;
691     resultSetAddRPN (zh, decode, stream, query, 
692                      zh->num_basenames, zh->basenames, setname);
693
694     zebra_end_read (zh);
695
696     *hits = zh->hits;
697 }
698
699 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
700                              const char *setname, Z_RecordComposition *comp,
701                              oid_value input_format, int num_recs,
702                              ZebraRetrievalRecord *recs)
703 {
704     ZebraPosSet poset;
705     int i, *pos_array;
706
707     if (!zh->res)
708     {
709         zh->errCode = 30;
710         zh->errString = odr_strdup (stream, setname);
711         return;
712     }
713     
714     zh->errCode = 0;
715
716     if (zebra_begin_read (zh))
717         return;
718
719     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
720     for (i = 0; i<num_recs; i++)
721         pos_array[i] = recs[i].position;
722     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
723     if (!poset)
724     {
725         logf (LOG_DEBUG, "zebraPosSetCreate error");
726         zh->errCode = 30;
727         zh->errString = nmem_strdup (stream->mem, setname);
728     }
729     else
730     {
731         for (i = 0; i<num_recs; i++)
732         {
733             if (poset[i].term)
734             {
735                 recs[i].errCode = 0;
736                 recs[i].format = VAL_SUTRS;
737                 recs[i].len = strlen(poset[i].term);
738                 recs[i].buf = poset[i].term;
739                 recs[i].base = poset[i].db;
740             }
741             else if (poset[i].sysno)
742             {
743                 recs[i].errCode =
744                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
745                                         stream, input_format, comp,
746                                         &recs[i].format, &recs[i].buf,
747                                         &recs[i].len,
748                                         &recs[i].base);
749                 recs[i].errString = NULL;
750             }
751             else
752             {
753                 char num_str[20];
754
755                 sprintf (num_str, "%d", pos_array[i]);  
756                 zh->errCode = 13;
757                 zh->errString = odr_strdup (stream, num_str);
758                 break;
759             }
760         }
761         zebraPosSetDestroy (zh, poset, num_recs);
762     }
763     zebra_end_read (zh);
764     xfree (pos_array);
765 }
766
767 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
768                  oid_value attributeset,
769                  int *position, int *num_entries, ZebraScanEntry **entries,
770                  int *is_partial)
771 {
772     if (zebra_begin_read (zh))
773     {
774         *entries = 0;
775         *num_entries = 0;
776         return;
777     }
778     rpn_scan (zh, stream, zapt, attributeset,
779               zh->num_basenames, zh->basenames, position,
780               num_entries, entries, is_partial);
781     zebra_end_read (zh);
782 }
783
784 void zebra_sort (ZebraHandle zh, ODR stream,
785                  int num_input_setnames, const char **input_setnames,
786                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
787                  int *sort_status)
788 {
789     if (zebra_begin_read (zh))
790         return;
791     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
792                    output_setname, sort_sequence, sort_status);
793     zebra_end_read(zh);
794 }
795
796 int zebra_deleleResultSet(ZebraHandle zh, int function,
797                           int num_setnames, char **setnames,
798                           int *statuses)
799 {
800     int i, status;
801     if (zebra_begin_read(zh))
802         return Z_DeleteStatus_systemProblemAtTarget;
803     switch (function)
804     {
805     case Z_DeleteRequest_list:
806         resultSetDestroy (zh, num_setnames, setnames, statuses);
807         break;
808     case Z_DeleteRequest_all:
809         resultSetDestroy (zh, -1, 0, statuses);
810         break;
811     }
812     zebra_end_read (zh);
813     status = Z_DeleteStatus_success;
814     for (i = 0; i<num_setnames; i++)
815         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
816             status = statuses[i];
817     return status;
818 }
819
820 int zebra_errCode (ZebraHandle zh)
821 {
822     return zh->errCode;
823 }
824
825 const char *zebra_errString (ZebraHandle zh)
826 {
827     return diagbib1_str (zh->errCode);
828 }
829
830 char *zebra_errAdd (ZebraHandle zh)
831 {
832     return zh->errString;
833 }
834
835 int zebra_auth (ZebraHandle zh, const char *user, const char *pass)
836 {
837     ZebraService zs = zh->service;
838     if (!zs->passwd_db || !passwd_db_auth (zs->passwd_db, user, pass))
839     {
840         logf(LOG_APP,"AUTHOK:%s", user?user:"ANONYMOUS");
841         return 0;
842     }
843
844     logf(LOG_APP,"AUTHFAIL:%s", user?user:"ANONYMOUS");
845     return 1;
846 }
847
848 void zebra_admin_import_begin (ZebraHandle zh, const char *database)
849 {
850     zebra_begin_trans (zh);
851     xfree (zh->admin_databaseName);
852     zh->admin_databaseName = xstrdup(database);
853 }
854
855 void zebra_admin_import_end (ZebraHandle zh)
856 {
857     zebra_end_trans (zh);
858 }
859
860 void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
861 {
862     int sysno;
863     int i;
864     for (i = 0; i<segment->num_segmentRecords; i++)
865     {
866         Z_NamePlusRecord *npr = segment->segmentRecords[i];
867         const char *databaseName = npr->databaseName;
868
869         if (!databaseName)
870             databaseName = zh->admin_databaseName;
871         printf ("--------------%d--------------------\n", i);
872         if (npr->which == Z_NamePlusRecord_intermediateFragment)
873         {
874             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
875             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
876             {
877                 Odr_oct *oct = fragment->u.notExternallyTagged;
878                 printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
879                         oct->buf);
880                 
881                 sysno = 0;
882                 extract_rec_in_mem (zh, "grs.sgml",
883                                     oct->buf, oct->len,
884                                     databaseName,
885                                     0 /* delete_flag */,
886                                     0 /* test_mode */,
887                                     &sysno /* sysno */,
888                                     1 /* store_keys */,
889                                     1 /* store_data */,
890                                     0 /* match criteria */);
891             }
892         }
893     }
894 }
895
896 void zebra_admin_create (ZebraHandle zh, const char *database)
897 {
898     ZebraService zs;
899
900     zebra_begin_trans (zh);
901
902     zs = zh->service;
903     /* announce database */
904     if (zebraExplain_newDatabase (zh->reg->zei, database, 0 
905                                   /* explainDatabase */))
906     {
907         zh->errCode = 224;
908         zh->errString = "Database already exist";
909     }
910     zebra_end_trans (zh);
911 }
912
913 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
914                        const char *input_str, int input_len,
915                        char *output_str, int output_len)
916 {
917     WRBUF wrbuf;
918     if (!zh->reg->zebra_maps)
919         return -1;
920     wrbuf = zebra_replace(zh->reg->zebra_maps, reg_id, "",
921                           input_str, input_len);
922     if (!wrbuf)
923         return -2;
924     if (wrbuf_len(wrbuf) >= output_len)
925         return -3;
926     if (wrbuf_len(wrbuf))
927         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
928     output_str[wrbuf_len(wrbuf)] = '\0';
929     return wrbuf_len(wrbuf);
930 }
931
932
933 void zebra_set_state (ZebraHandle zh, int val, int seqno)
934 {
935     char state_fname[256];
936     char *fname;
937     long p = getpid();
938     FILE *f;
939
940     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
941     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
942     f = fopen (fname, "w");
943
944     yaz_log (LOG_LOG, "%c %d %ld", val, seqno, p);
945     fprintf (f, "%c %d %ld\n", val, seqno, p);
946     fclose (f);
947     xfree (fname);
948 }
949
950 void zebra_get_state (ZebraHandle zh, char *val, int *seqno)
951 {
952     char state_fname[256];
953     char *fname;
954     FILE *f;
955
956     sprintf (state_fname, "state.%s.LCK", zh->reg_name);
957     fname = zebra_mk_fname (res_get(zh->res, "lockDir"), state_fname);
958     f = fopen (fname, "r");
959     *val = 'o';
960     *seqno = 0;
961
962     if (f)
963     {
964         fscanf (f, "%c %d", val, seqno);
965         fclose (f);
966     }
967     xfree (fname);
968 }
969
970 int zebra_begin_read (ZebraHandle zh)
971 {
972     int dirty = 0;
973     char val;
974     int seqno;
975
976     assert (zh->res);
977
978     (zh->trans_no)++;
979
980     if (zh->trans_no != 1)
981     {
982         zebra_flush_reg (zh);
983         return 0;
984     }
985 #if HAVE_SYS_TIMES_H
986     times (&zh->tms1);
987 #endif
988     if (!zh->res)
989     {
990         (zh->trans_no)--;
991         zh->errCode = 109;
992         return -1;
993     }
994     zebra_get_state (zh, &val, &seqno);
995     if (val == 'd')
996         val = 'o';
997
998     if (!zh->reg)
999         dirty = 1;
1000     else if (seqno != zh->reg->seqno)
1001     {
1002         yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d",
1003                  seqno, zh->reg->seqno);
1004         dirty = 1;
1005     }
1006     else if (zh->reg->last_val != val)
1007     {
1008         yaz_log (LOG_LOG, "reopen last cur/old %d/%d",
1009                  val, zh->reg->last_val);
1010         dirty = 1;
1011     }
1012     if (!dirty)
1013         return 0;
1014
1015     if (val == 'c')
1016         zebra_lock_r (zh->lock_shadow);
1017     else
1018         zebra_lock_r (zh->lock_normal);
1019     
1020     if (zh->reg)
1021         zebra_register_close (zh->service, zh->reg);
1022     zh->reg = zebra_register_open (zh->service, zh->reg_name,
1023                                    0, val == 'c' ? 1 : 0,
1024                                    zh->res, zh->path_reg);
1025     if (!zh->reg)
1026     {
1027         zh->errCode = 109;
1028         return -1;
1029     }
1030     zh->reg->last_val = val;
1031     zh->reg->seqno = seqno;
1032
1033     return 0;
1034 }
1035
1036 void zebra_end_read (ZebraHandle zh)
1037 {
1038     (zh->trans_no)--;
1039
1040     if (zh->trans_no != 0)
1041         return;
1042
1043 #if HAVE_SYS_TIMES_H
1044     times (&zh->tms2);
1045     logf (LOG_LOG, "user/system: %ld/%ld",
1046                     (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
1047                     (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
1048
1049 #endif
1050
1051     zebra_unlock (zh->lock_normal);
1052     zebra_unlock (zh->lock_shadow);
1053 }
1054
1055 void zebra_begin_trans (ZebraHandle zh)
1056 {
1057     int pass;
1058     int seqno = 0;
1059     char val = '?';
1060     const char *rval = 0;
1061
1062     assert (zh->res);
1063
1064     (zh->trans_no++);
1065     if (zh->trans_no != 1)
1066     {
1067         return;
1068     }
1069     
1070     yaz_log (LOG_LOG, "zebra_begin_trans");
1071
1072     zh->records_inserted = 0;
1073     zh->records_updated = 0;
1074     zh->records_deleted = 0;
1075     zh->records_processed = 0;
1076
1077 #if HAVE_SYS_TIMES_H
1078     times (&zh->tms1);
1079 #endif
1080     
1081     /* lock */
1082     if (zh->shadow_enable)
1083         rval = res_get (zh->res, "shadow");
1084
1085     for (pass = 0; pass < 2; pass++)
1086     {
1087         if (rval)
1088         {
1089             zebra_lock_r (zh->lock_normal);
1090             zebra_lock_w (zh->lock_shadow);
1091         }
1092         else
1093         {
1094             zebra_lock_w (zh->lock_normal);
1095             zebra_lock_w (zh->lock_shadow);
1096         }
1097         
1098         zebra_get_state (zh, &val, &seqno);
1099         if (val == 'c')
1100         {
1101             yaz_log (LOG_LOG, "previous transaction didn't finish commit");
1102             zebra_unlock (zh->lock_shadow);
1103             zebra_unlock (zh->lock_normal);
1104             zebra_commit (zh);
1105             continue;
1106         }
1107         else if (val == 'd')
1108         {
1109             if (rval)
1110             {
1111                 BFiles bfs = bfs_create (res_get (zh->res, "shadow"),
1112                                          zh->path_reg);
1113                 yaz_log (LOG_LOG, "previous transaction didn't reach commit");
1114                 bf_commitClean (bfs, rval);
1115                 bfs_destroy (bfs);
1116             }
1117             else
1118             {
1119                 yaz_log (LOG_WARN, "your previous transaction didn't finish");
1120             }
1121         }
1122         break;
1123     }
1124     if (pass == 2)
1125     {
1126         yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
1127         abort();
1128         return;
1129     }
1130     zebra_set_state (zh, 'd', seqno);
1131
1132     zh->reg = zebra_register_open (zh->service, zh->reg_name,
1133                                    1, rval ? 1 : 0, zh->res,
1134                                    zh->path_reg);
1135
1136     zh->reg->seqno = seqno;
1137 }
1138
1139 void zebra_end_trans (ZebraHandle zh)
1140 {
1141     char val;
1142     int seqno;
1143     const char *rval;
1144
1145     zh->trans_no--;
1146     if (zh->trans_no != 0)
1147         return;
1148
1149     yaz_log (LOG_LOG, "zebra_end_trans");
1150     rval = res_get (zh->res, "shadow");
1151
1152     zebraExplain_runNumberIncrement (zh->reg->zei, 1);
1153
1154     zebra_flush_reg (zh);
1155
1156     zebra_register_close (zh->service, zh->reg);
1157     zh->reg = 0;
1158
1159     
1160     yaz_log (LOG_LOG, "Records: %7d i/u/d %d/%d/%d", 
1161              zh->records_processed, zh->records_inserted,
1162              zh->records_updated, zh->records_deleted);
1163
1164     zebra_get_state (zh, &val, &seqno);
1165     if (val != 'd')
1166     {
1167         BFiles bfs = bfs_create (rval, zh->path_reg);
1168         yaz_log (LOG_LOG, "deleting shadow stuff val=%c", val);
1169         bf_commitClean (bfs, rval);
1170         bfs_destroy (bfs);
1171     }
1172     if (!rval)
1173         seqno++;
1174     zebra_set_state (zh, 'o', seqno);
1175
1176     zebra_unlock (zh->lock_shadow);
1177     zebra_unlock (zh->lock_normal);
1178
1179 #if HAVE_SYS_TIMES_H
1180     times (&zh->tms2);
1181     logf (LOG_LOG, "user/system: %ld/%ld",
1182                     (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
1183                     (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
1184
1185 #endif
1186 }
1187
1188 void zebra_repository_update (ZebraHandle zh)
1189 {
1190     zebra_begin_trans (zh);
1191     logf (LOG_LOG, "updating %s", zh->rGroup.path);
1192     repositoryUpdate (zh);    
1193     zebra_end_trans (zh);
1194 }
1195
1196 void zebra_repository_delete (ZebraHandle zh)
1197 {
1198     logf (LOG_LOG, "deleting %s", zh->rGroup.path);
1199     repositoryDelete (zh);
1200 }
1201
1202 void zebra_repository_show (ZebraHandle zh)
1203 {
1204     repositoryShow (zh);
1205 }
1206
1207 int zebra_commit (ZebraHandle zh)
1208 {
1209     int seqno;
1210     char val;
1211     const char *rval;
1212     BFiles bfs;
1213
1214     if (!zh->res)
1215     {
1216         zh->errCode = 109;
1217         return -1;
1218     }
1219     rval = res_get (zh->res, "shadow");    
1220     if (!rval)
1221     {
1222         logf (LOG_WARN, "Cannot perform commit");
1223         logf (LOG_WARN, "No shadow area defined");
1224         return 0;
1225     }
1226
1227     zebra_lock_w (zh->lock_normal);
1228     zebra_lock_r (zh->lock_shadow);
1229
1230     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
1231
1232     zebra_get_state (zh, &val, &seqno);
1233
1234     if (rval && *rval)
1235         bf_cache (bfs, rval);
1236     if (bf_commitExists (bfs))
1237     {
1238         zebra_set_state (zh, 'c', seqno);
1239
1240         logf (LOG_LOG, "commit start");
1241         bf_commitExec (bfs);
1242 #ifndef WIN32
1243         sync ();
1244 #endif
1245         logf (LOG_LOG, "commit clean");
1246         bf_commitClean (bfs, rval);
1247         seqno++;
1248         zebra_set_state (zh, 'o', seqno);
1249     }
1250     else
1251     {
1252         logf (LOG_LOG, "nothing to commit");
1253     }
1254     bfs_destroy (bfs);
1255
1256     zebra_unlock (zh->lock_shadow);
1257     zebra_unlock (zh->lock_normal);
1258     return 0;
1259 }
1260
1261 int zebra_init (ZebraHandle zh)
1262 {
1263     const char *rval;
1264     BFiles bfs = 0;
1265
1266     if (!zh->res)
1267     {
1268         zh->errCode = 109;
1269         return -1;
1270     }
1271     rval = res_get (zh->res, "shadow");
1272
1273     bfs = bfs_create (res_get (zh->service->global_res, "register"),
1274                       zh->path_reg);
1275     if (rval && *rval)
1276         bf_cache (bfs, rval);
1277     
1278     bf_reset (bfs);
1279     bfs_destroy (bfs);
1280     zebra_set_state (zh, 'o', 0);
1281     return 0;
1282 }
1283
1284 int zebra_compact (ZebraHandle zh)
1285 {
1286     BFiles bfs;
1287     if (!zh->res)
1288     {
1289         zh->errCode = 109;
1290         return -1;
1291     }
1292     bfs = bfs_create (res_get (zh->res, "register"), zh->path_reg);
1293     inv_compact (bfs);
1294     bfs_destroy (bfs);
1295     return 0;
1296 }
1297
1298 int zebra_record_insert (ZebraHandle zh, const char *buf, int len)
1299 {
1300     int sysno = 0;
1301     zebra_begin_trans (zh);
1302     extract_rec_in_mem (zh, "grs.sgml",
1303                         buf, len,
1304                         "Default",  /* database */
1305                         0 /* delete_flag */,
1306                         0 /* test_mode */,
1307                         &sysno /* sysno */,
1308                         1 /* store_keys */,
1309                         1 /* store_data */,
1310                         0 /* match criteria */);
1311     zebra_end_trans (zh);
1312     return sysno;
1313 }
1314
1315 void zebra_set_group (ZebraHandle zh, struct recordGroup *rg)
1316 {
1317     memcpy (&zh->rGroup, rg, sizeof(*rg));
1318 }
1319
1320 void zebra_result (ZebraHandle zh, int *code, char **addinfo)
1321 {
1322     *code = zh->errCode;
1323     *addinfo = zh->errString;
1324 }
1325
1326 void zebra_shadow_enable (ZebraHandle zh, int value)
1327 {
1328     zh->shadow_enable = value;
1329 }
1330
1331 int zebra_record_encoding (ZebraHandle zh, const char *encoding)
1332 {
1333     xfree (zh->record_encoding);
1334     zh->record_encoding = xstrdup (encoding);
1335     return 0;
1336 }