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