Hits per term. Returned in SearchResult-1
[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.48 2002-03-20 20:24:29 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 "zserver.h"
20 #include <charmap.h>
21
22 static void zebra_chdir (ZebraService zh)
23 {
24     const char *dir = res_get (zh->res, "chdir");
25     if (!dir)
26         return;
27     logf (LOG_DEBUG, "chdir %s", dir);
28 #ifdef WIN32
29     _chdir(dir);
30 #else
31     chdir (dir);
32 #endif
33 }
34
35 static void zebra_flush_reg (ZebraHandle zh)
36 {
37     zebraExplain_flush (zh->service->zei, 1, zh);
38     
39     extract_flushWriteKeys (zh);
40     zebra_index_merge (zh);
41 }
42
43
44 static int zebra_register_activate (ZebraHandle zh, int rw, int useshadow);
45 static int zebra_register_deactivate (ZebraHandle zh);
46
47 static int zebra_begin_read (ZebraHandle zh);
48 static void zebra_end_read (ZebraHandle zh);
49
50 ZebraHandle zebra_open (ZebraService zs)
51 {
52     ZebraHandle zh;
53
54     assert (zs);
55     if (zs->stop_flag)
56         return 0;
57
58     zh = (ZebraHandle) xmalloc (sizeof(*zh));
59     yaz_log (LOG_LOG, "zebra_open zs=%p returns %p", zs, zh);
60
61     zh->service = zs;
62     zh->sets = 0;
63     zh->destroyed = 0;
64     zh->errCode = 0;
65     zh->errString = 0;
66
67     zh->trans_no = 0;
68     zh->seqno = 0;
69     zh->last_val = 0;
70
71     zh->lock_normal = zebra_lock_create ("norm.LCK", 0);
72     zh->lock_shadow = zebra_lock_create ("shadow.LCK", 0);
73
74     zh->key_buf = 0;
75     zh->admin_databaseName = 0;
76
77     zh->keys.buf_max = 0;
78     zh->keys.buf = 0;
79
80     zebra_mutex_cond_lock (&zs->session_lock);
81
82     zh->next = zs->sessions;
83     zs->sessions = zh;
84
85     zebra_mutex_cond_unlock (&zs->session_lock);
86
87     return zh;
88 }
89
90
91 ZebraService zebra_start (const char *configName)
92 {
93     ZebraService zh = xmalloc (sizeof(*zh));
94
95     yaz_log (LOG_LOG, "zebra_start %s", configName);
96
97     zh->configName = xstrdup(configName);
98     zh->sessions = 0;
99     zh->stop_flag = 0;
100     zh->active = 1;
101
102     zh->registerState = -1;
103     zh->registerChange = 0;
104
105     if (!(zh->res = res_open (zh->configName)))
106     {
107         logf (LOG_WARN, "Failed to read resources `%s'", zh->configName);
108 //      return zh;
109     }
110     zebra_chdir (zh);
111
112     zebra_mutex_cond_init (&zh->session_lock);
113     if (!res_get (zh->res, "passwd"))
114         zh->passwd_db = NULL;
115     else
116     {
117         zh->passwd_db = passwd_db_open ();
118         if (!zh->passwd_db)
119             logf (LOG_WARN|LOG_ERRNO, "passwd_db_open failed");
120         else
121             passwd_db_file (zh->passwd_db, res_get (zh->res, "passwd"));
122     }
123
124     return zh;
125 }
126
127 static int zebra_register_activate (ZebraHandle zh, int rw, int useshadow)
128 {
129     ZebraService zs = zh->service;
130     int record_compression = REC_COMPRESS_NONE;
131     char *recordCompression = 0;
132
133     yaz_log (LOG_LOG, "zebra_open_register_activate rw = %d useshadow=%d",
134              rw, useshadow);
135
136     zs->dh = data1_create ();
137     if (!zs->dh)
138         return -1;
139     zs->bfs = bfs_create (res_get (zs->res, "register"));
140     if (!zs->bfs)
141     {
142         data1_destroy(zs->dh);
143         return -1;
144     }
145     bf_lockDir (zs->bfs, res_get (zs->res, "lockDir"));
146     if (useshadow)
147         bf_cache (zs->bfs, res_get (zs->res, "shadow"));
148     data1_set_tabpath (zs->dh, res_get(zs->res, "profilePath"));
149     zs->recTypes = recTypes_init (zs->dh);
150     recTypes_default_handlers (zs->recTypes);
151
152     zs->zebra_maps = zebra_maps_open (zs->res);
153     zs->rank_classes = NULL;
154
155     zs->records = 0;
156     zs->dict = 0;
157     zs->sortIdx = 0;
158     zs->isams = 0;
159     zs->matchDict = 0;
160 #if ZMBOL
161     zs->isam = 0;
162     zs->isamc = 0;
163     zs->isamd = 0;
164 #endif
165     zs->zei = 0;
166     zs->matchDict = 0;
167     
168     zebraRankInstall (zs, rank1_class);
169
170     recordCompression = res_get_def (zh->service->res,
171                                      "recordCompression", "none");
172     if (!strcmp (recordCompression, "none"))
173         record_compression = REC_COMPRESS_NONE;
174     if (!strcmp (recordCompression, "bzip2"))
175         record_compression = REC_COMPRESS_BZIP2;
176
177     if (!(zs->records = rec_open (zs->bfs, rw, record_compression)))
178     {
179         logf (LOG_WARN, "rec_open");
180         return -1;
181     }
182     if (rw)
183     {
184         zs->matchDict = dict_open (zs->bfs, GMATCH_DICT, 20, 1, 0);
185     }
186     if (!(zs->dict = dict_open (zs->bfs, FNAME_DICT, 40, rw, 0)))
187     {
188         logf (LOG_WARN, "dict_open");
189         return -1;
190     }
191     if (!(zs->sortIdx = sortIdx_open (zs->bfs, rw)))
192     {
193         logf (LOG_WARN, "sortIdx_open");
194         return -1;
195     }
196     if (res_get_match (zs->res, "isam", "s", ISAM_DEFAULT))
197     {
198         struct ISAMS_M_s isams_m;
199         if (!(zs->isams = isams_open (zs->bfs, FNAME_ISAMS, rw,
200                                       key_isams_m(zs->res, &isams_m))))
201         {
202             logf (LOG_WARN, "isams_open");
203             return -1;
204         }
205     }
206 #if ZMBOL
207     else if (res_get_match (zs->res, "isam", "i", ISAM_DEFAULT))
208     {
209         if (!(zs->isam = is_open (zs->bfs, FNAME_ISAM, key_compare, rw,
210                                   sizeof (struct it_key), zs->res)))
211         {
212             logf (LOG_WARN, "is_open");
213             return -1;
214         }
215     }
216     else if (res_get_match (zs->res, "isam", "c", ISAM_DEFAULT))
217     {
218         struct ISAMC_M_s isamc_m;
219         if (!(zs->isamc = isc_open (zs->bfs, FNAME_ISAMC,
220                                     rw, key_isamc_m(zs->res, &isamc_m))))
221         {
222             logf (LOG_WARN, "isc_open");
223             return -1;
224         }
225     }
226     else if (res_get_match (zs->res, "isam", "d", ISAM_DEFAULT))
227     {
228         struct ISAMD_M_s isamd_m;
229         
230         if (!(zs->isamd = isamd_open (zs->bfs, FNAME_ISAMD,
231                                       rw, key_isamd_m(zs->res, &isamd_m))))
232         {
233             logf (LOG_WARN, "isamd_open");
234             return -1;
235         }
236     }
237 #endif
238     zs->zei = zebraExplain_open (zs->records, zs->dh,
239                                  zs->res, rw, zh,
240                                  explain_extract);
241     if (!zs->zei)
242     {
243         logf (LOG_WARN, "Cannot obtain EXPLAIN information");
244         return -1;
245     }
246     zs->active = 2;
247     yaz_log (LOG_LOG, "zebra_register_activate ok");
248     return 0;
249 }
250
251 void zebra_admin_shutdown (ZebraHandle zh)
252 {
253     zebra_mutex_cond_lock (&zh->service->session_lock);
254     zh->service->stop_flag = 1;
255     if (!zh->service->sessions)
256         zebra_register_deactivate(zh);
257     zh->service->active = 0;
258     zebra_mutex_cond_unlock (&zh->service->session_lock);
259 }
260
261 void zebra_admin_start (ZebraHandle zh)
262 {
263     ZebraService zs = zh->service;
264     zh->errCode = 0;
265     zebra_mutex_cond_lock (&zs->session_lock);
266     if (!zs->stop_flag)
267         zh->service->active = 1;
268     zebra_mutex_cond_unlock (&zs->session_lock);
269 }
270
271 static int zebra_register_deactivate (ZebraHandle zh)
272 {
273     ZebraService zs = zh->service;
274     zs->stop_flag = 0;
275     if (zs->active <= 1)
276     {
277         yaz_log(LOG_LOG, "zebra_register_deactivate (ignored since active=%d)",
278                 zs->active);
279         return 0;
280     }
281     yaz_log(LOG_LOG, "zebra_register_deactivate");
282     zebra_chdir (zs);
283     if (zs->records)
284     {
285         zebraExplain_close (zs->zei, 0);
286         dict_close (zs->dict);
287         if (zs->matchDict)
288             dict_close (zs->matchDict);
289         sortIdx_close (zs->sortIdx);
290         if (zs->isams)
291             isams_close (zs->isams);
292 #if ZMBOL
293         if (zs->isam)
294             is_close (zs->isam);
295         if (zs->isamc)
296             isc_close (zs->isamc);
297         if (zs->isamd)
298             isamd_close (zs->isamd);
299 #endif
300         rec_close (&zs->records);
301     }
302     resultSetInvalidate (zh);
303
304     recTypes_destroy (zs->recTypes);
305     zebra_maps_close (zs->zebra_maps);
306     zebraRankDestroy (zs);
307     bfs_destroy (zs->bfs);
308     data1_destroy (zs->dh);
309
310     if (zs->passwd_db)
311         passwd_db_close (zs->passwd_db);
312     zs->active = 1;
313     return 0;
314 }
315
316 void zebra_stop(ZebraService zs)
317 {
318     if (!zs)
319         return ;
320     yaz_log (LOG_LOG, "zebra_stop");
321
322     zebra_mutex_cond_lock (&zs->session_lock);
323     while (zs->sessions)
324     {
325         zebra_register_deactivate(zs->sessions);
326         zebra_close (zs->sessions);
327     }
328         
329     zebra_mutex_cond_unlock (&zs->session_lock);
330
331     zebra_mutex_cond_destroy (&zs->session_lock);
332
333     res_close (zs->res);
334     xfree (zs->configName);
335     xfree (zs);
336 }
337
338 void zebra_close (ZebraHandle zh)
339 {
340     ZebraService zs;
341     struct zebra_session **sp;
342
343     if (!zh)
344         return;
345
346     zs = zh->service;
347     yaz_log (LOG_LOG, "zebra_close zh=%p", zh);
348     if (!zh)
349         return ;
350     resultSetDestroy (zh, -1, 0, 0);
351
352     if (zh->key_buf)
353     {
354         xfree (zh->key_buf);
355         zh->key_buf = 0;
356     }
357     
358     xfree (zh->admin_databaseName);
359     zebra_mutex_cond_lock (&zs->session_lock);
360     zebra_lock_destroy (zh->lock_normal);
361     zebra_lock_destroy (zh->lock_shadow);
362     sp = &zs->sessions;
363     while (1)
364     {
365         assert (*sp);
366         if (*sp == zh)
367         {
368             *sp = (*sp)->next;
369             break;
370         }
371         sp = &(*sp)->next;
372     }
373 //    if (!zs->sessions && zs->stop_flag)
374 //      zebra_register_deactivate(zs);
375     zebra_mutex_cond_unlock (&zs->session_lock);
376     xfree (zh);
377 }
378
379 struct map_baseinfo {
380     ZebraHandle zh;
381     NMEM mem;
382     int num_bases;
383     char **basenames;
384     int new_num_bases;
385     char **new_basenames;
386     int new_num_max;
387 };
388         
389 void map_basenames_func (void *vp, const char *name, const char *value)
390 {
391     struct map_baseinfo *p = (struct map_baseinfo *) vp;
392     int i, no;
393     char fromdb[128], todb[8][128];
394     
395     no =
396         sscanf (value, "%127s %127s %127s %127s %127s %127s %127s %127s %127s",
397                 fromdb, todb[0], todb[1], todb[2], todb[3], todb[4],
398                 todb[5], todb[6], todb[7]);
399     if (no < 2)
400         return ;
401     no--;
402     for (i = 0; i<p->num_bases; i++)
403         if (p->basenames[i] && !strcmp (p->basenames[i], fromdb))
404         {
405             p->basenames[i] = 0;
406             for (i = 0; i < no; i++)
407             {
408                 if (p->new_num_bases == p->new_num_max)
409                     return;
410                 p->new_basenames[(p->new_num_bases)++] = 
411                     nmem_strdup (p->mem, todb[i]);
412             }
413             return;
414         }
415 }
416
417 void map_basenames (ZebraHandle zh, ODR stream,
418                     int *num_bases, char ***basenames)
419 {
420     struct map_baseinfo info;
421     struct map_baseinfo *p = &info;
422     int i;
423
424     info.zh = zh;
425     info.num_bases = *num_bases;
426     info.basenames = *basenames;
427     info.new_num_max = 128;
428     info.new_num_bases = 0;
429     info.new_basenames = (char **)
430         odr_malloc (stream, sizeof(*info.new_basenames) * info.new_num_max);
431     info.mem = stream->mem;
432
433     res_trav (zh->service->res, "mapdb", &info, map_basenames_func);
434     
435     for (i = 0; i<p->num_bases; i++)
436         if (p->basenames[i] && p->new_num_bases < p->new_num_max)
437         {
438             p->new_basenames[(p->new_num_bases)++] = 
439                 nmem_strdup (p->mem, p->basenames[i]);
440         }
441     *num_bases = info.new_num_bases;
442     *basenames = info.new_basenames;
443     for (i = 0; i<*num_bases; i++)
444         logf (LOG_LOG, "base %s", (*basenames)[i]);
445 }
446
447 void zebra_search_rpn (ZebraHandle zh, ODR stream, ODR decode,
448                        Z_RPNQuery *query, int num_bases, char **basenames, 
449                        const char *setname)
450 {
451     zh->hits = 0;
452     if (zebra_begin_read (zh))
453         return;
454     map_basenames (zh, stream, &num_bases, &basenames);
455     resultSetAddRPN (zh, stream, decode, query, num_bases, basenames, setname);
456
457     zebra_end_read (zh);
458
459     logf(LOG_APP,"SEARCH:%d:",zh->hits);
460 }
461
462
463
464 void zebra_records_retrieve (ZebraHandle zh, ODR stream,
465                              const char *setname, Z_RecordComposition *comp,
466                              oid_value input_format, int num_recs,
467                              ZebraRetrievalRecord *recs)
468 {
469     ZebraPosSet poset;
470     int i, *pos_array;
471
472     if (zebra_begin_read (zh))
473         return;
474
475     pos_array = (int *) xmalloc (num_recs * sizeof(*pos_array));
476     for (i = 0; i<num_recs; i++)
477         pos_array[i] = recs[i].position;
478     poset = zebraPosSetCreate (zh, setname, num_recs, pos_array);
479     if (!poset)
480     {
481         logf (LOG_DEBUG, "zebraPosSetCreate error");
482         zh->errCode = 30;
483         zh->errString = nmem_strdup (stream->mem, setname);
484     }
485     else
486     {
487         for (i = 0; i<num_recs; i++)
488         {
489             if (poset[i].term)
490             {
491                 recs[i].errCode = 0;
492                 recs[i].format = VAL_SUTRS;
493                 recs[i].len = strlen(poset[i].term);
494                 recs[i].buf = poset[i].term;
495                 recs[i].base = poset[i].db;
496             }
497             else if (poset[i].sysno)
498             {
499                 recs[i].errCode =
500                     zebra_record_fetch (zh, poset[i].sysno, poset[i].score,
501                                         stream, input_format, comp,
502                                         &recs[i].format, &recs[i].buf,
503                                         &recs[i].len,
504                                         &recs[i].base);
505                 recs[i].errString = NULL;
506             }
507             else
508             {
509                 char num_str[20];
510
511                 sprintf (num_str, "%d", pos_array[i]);  
512                 zh->errCode = 13;
513                 zh->errString = nmem_strdup (stream->mem, num_str);
514                 break;
515             }
516         }
517         zebraPosSetDestroy (zh, poset, num_recs);
518     }
519     zebra_end_read (zh);
520     xfree (pos_array);
521 }
522
523 void zebra_scan (ZebraHandle zh, ODR stream, Z_AttributesPlusTerm *zapt,
524                  oid_value attributeset,
525                  int num_bases, char **basenames,
526                  int *position, int *num_entries, ZebraScanEntry **entries,
527                  int *is_partial)
528 {
529     if (zebra_begin_read (zh))
530     {
531         *entries = 0;
532         *num_entries = 0;
533         return;
534     }
535     map_basenames (zh, stream, &num_bases, &basenames);
536     rpn_scan (zh, stream, zapt, attributeset,
537               num_bases, basenames, position,
538               num_entries, entries, is_partial);
539     zebra_end_read (zh);
540 }
541
542 void zebra_sort (ZebraHandle zh, ODR stream,
543                  int num_input_setnames, const char **input_setnames,
544                  const char *output_setname, Z_SortKeySpecList *sort_sequence,
545                  int *sort_status)
546 {
547     if (zebra_begin_read (zh))
548         return;
549     resultSetSort (zh, stream->mem, num_input_setnames, input_setnames,
550                    output_setname, sort_sequence, sort_status);
551     zebra_end_read(zh);
552 }
553
554 int zebra_deleleResultSet(ZebraHandle zh, int function,
555                           int num_setnames, char **setnames,
556                           int *statuses)
557 {
558     int i, status;
559     if (zebra_begin_read(zh))
560         return Z_DeleteStatus_systemProblemAtTarget;
561     switch (function)
562     {
563     case Z_DeleteRequest_list:
564         resultSetDestroy (zh, num_setnames, setnames, statuses);
565         break;
566     case Z_DeleteRequest_all:
567         resultSetDestroy (zh, -1, 0, statuses);
568         break;
569     }
570     zebra_end_read (zh);
571     status = Z_DeleteStatus_success;
572     for (i = 0; i<num_setnames; i++)
573         if (statuses[i] == Z_DeleteStatus_resultSetDidNotExist)
574             status = statuses[i];
575     return status;
576 }
577
578 int zebra_errCode (ZebraHandle zh)
579 {
580     return zh->errCode;
581 }
582
583 const char *zebra_errString (ZebraHandle zh)
584 {
585     return diagbib1_str (zh->errCode);
586 }
587
588 char *zebra_errAdd (ZebraHandle zh)
589 {
590     return zh->errString;
591 }
592
593 int zebra_hits (ZebraHandle zh)
594 {
595     return zh->hits;
596 }
597
598 int zebra_auth (ZebraService zh, const char *user, const char *pass)
599 {
600     if (!zh->passwd_db || !passwd_db_auth (zh->passwd_db, user, pass))
601     {
602         logf(LOG_APP,"AUTHOK:%s", user?user:"ANONYMOUS");
603         return 0;
604     }
605
606     logf(LOG_APP,"AUTHFAIL:%s", user?user:"ANONYMOUS");
607     return 1;
608 }
609
610 void zebra_admin_import_begin (ZebraHandle zh, const char *database)
611 {
612     zebra_begin_trans (zh);
613     xfree (zh->admin_databaseName);
614     zh->admin_databaseName = xstrdup(database);
615 }
616
617 void zebra_admin_import_end (ZebraHandle zh)
618 {
619     zebra_end_trans (zh);
620 }
621
622 void zebra_admin_import_segment (ZebraHandle zh, Z_Segment *segment)
623 {
624     int sysno;
625     int i;
626     if (zh->service->active < 2)
627         return;
628     for (i = 0; i<segment->num_segmentRecords; i++)
629     {
630         Z_NamePlusRecord *npr = segment->segmentRecords[i];
631         const char *databaseName = npr->databaseName;
632
633         if (!databaseName)
634             databaseName = zh->admin_databaseName;
635         printf ("--------------%d--------------------\n", i);
636         if (npr->which == Z_NamePlusRecord_intermediateFragment)
637         {
638             Z_FragmentSyntax *fragment = npr->u.intermediateFragment;
639             if (fragment->which == Z_FragmentSyntax_notExternallyTagged)
640             {
641                 Odr_oct *oct = fragment->u.notExternallyTagged;
642                 printf ("%.*s", (oct->len > 100 ? 100 : oct->len) ,
643                         oct->buf);
644                 
645                 sysno = 0;
646                 extract_rec_in_mem (zh, "grs.sgml",
647                                     oct->buf, oct->len,
648                                     databaseName,
649                                     0 /* delete_flag */,
650                                     0 /* test_mode */,
651                                     &sysno /* sysno */,
652                                     1 /* store_keys */,
653                                     1 /* store_data */,
654                                     0 /* match criteria */);
655             }
656         }
657     }
658 }
659
660 void zebra_admin_create (ZebraHandle zh, const char *database)
661 {
662     ZebraService zs;
663
664     zebra_begin_trans (zh);
665
666     zs = zh->service;
667     /* announce database */
668     if (zebraExplain_newDatabase (zh->service->zei, database, 0 
669                                   /* explainDatabase */))
670     {
671         zh->errCode = 224;
672         zh->errString = "Database already exist";
673     }
674     zebra_end_trans (zh);
675 }
676
677 int zebra_string_norm (ZebraHandle zh, unsigned reg_id,
678                        const char *input_str, int input_len,
679                        char *output_str, int output_len)
680 {
681     WRBUF wrbuf;
682     if (!zh->service->zebra_maps)
683         return -1;
684     wrbuf = zebra_replace(zh->service->zebra_maps, reg_id, "",
685                           input_str, input_len);
686     if (!wrbuf)
687         return -2;
688     if (wrbuf_len(wrbuf) >= output_len)
689         return -3;
690     if (wrbuf_len(wrbuf))
691         memcpy (output_str, wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
692     output_str[wrbuf_len(wrbuf)] = '\0';
693     return wrbuf_len(wrbuf);
694 }
695
696
697 void zebra_set_state (int val, int seqno)
698 {
699     long p = getpid();
700     FILE *f = fopen ("state.LCK", "w");
701     fprintf (f, "%c %d %ld\n", val, seqno, p);
702     fclose (f);
703 }
704
705 void zebra_get_state (char *val, int *seqno)
706 {
707     FILE *f = fopen ("state.LCK", "r");
708
709     *val = 'o';
710     *seqno = 0;
711
712     if (f)
713     {
714         fscanf (f, "%c %d", val, seqno);
715         fclose (f);
716     }
717 }
718
719 static int zebra_begin_read (ZebraHandle zh)
720 {
721     int dirty = 0;
722     char val;
723     int seqno;
724
725
726     (zh->trans_no)++;
727
728     if (zh->trans_no != 1)
729     {
730         zebra_flush_reg (zh);
731         return 0;
732     }
733
734     zebra_get_state (&val, &seqno);
735     if (val == 'd')
736         val = 'o';
737     if (seqno != zh->seqno)
738     {
739         yaz_log (LOG_LOG, "reopen seqno cur/old %d/%d", seqno, zh->seqno);
740         dirty = 1;
741     }
742     else if (zh->last_val != val)
743     {
744         yaz_log (LOG_LOG, "reopen last cur/old %d/%d", val, zh->last_val);
745         dirty = 1;
746     }
747     if (!dirty)
748         return 0;
749
750     if (val == 'c')
751         zebra_lock_r (zh->lock_shadow);
752     else
753         zebra_lock_r (zh->lock_normal);
754     
755     zh->last_val = val;
756     zh->seqno = seqno;
757
758     zebra_register_deactivate (zh);
759
760     zebra_register_activate (zh, 0, val == 'c' ? 1 : 0);
761     return 0;
762 }
763
764 static void zebra_end_read (ZebraHandle zh)
765 {
766     (zh->trans_no)--;
767
768     if (zh->trans_no != 0)
769         return;
770
771     zebra_unlock (zh->lock_normal);
772     zebra_unlock (zh->lock_shadow);
773 }
774
775 void zebra_begin_trans (ZebraHandle zh)
776 {
777     int pass;
778     int seqno = 0;
779     char val = '?';
780     const char *rval;
781
782     (zh->trans_no++);
783     if (zh->trans_no != 1)
784     {
785         return;
786     }
787
788     yaz_log (LOG_LOG, "zebra_begin_trans");
789 #if HAVE_SYS_TIMES_H
790     times (&zh->tms1);
791 #endif
792
793     /* lock */
794     rval = res_get (zh->service->res, "shadow");
795
796     for (pass = 0; pass < 2; pass++)
797     {
798         if (rval)
799         {
800             zebra_lock_r (zh->lock_normal);
801             zebra_lock_w (zh->lock_shadow);
802         }
803         else
804         {
805             zebra_lock_w (zh->lock_normal);
806             zebra_lock_w (zh->lock_shadow);
807         }
808         
809         zebra_get_state (&val, &seqno);
810         if (val == 'c')
811         {
812             yaz_log (LOG_LOG, "previous transaction didn't finish commit");
813             zebra_unlock (zh->lock_shadow);
814             zebra_unlock (zh->lock_normal);
815             zebra_commit (zh);
816             continue;
817         }
818         else if (val == 'd')
819         {
820             if (rval)
821             {
822                 BFiles bfs = bfs_create (res_get (zh->service->res, "shadow"));
823                 yaz_log (LOG_LOG, "previous transaction didn't reach commit");
824                 bf_commitClean (bfs, rval);
825                 bfs_destroy (bfs);
826             }
827             else
828             {
829                 yaz_log (LOG_WARN, "your previous transaction didn't finish");
830             }
831         }
832         break;
833     }
834     if (pass == 2)
835     {
836         yaz_log (LOG_FATAL, "zebra_begin_trans couldn't finish commit");
837         abort();
838         return;
839     }
840     zebra_set_state ('d', seqno);
841
842     zebra_register_activate (zh, 1, rval ? 1 : 0);
843     zh->seqno = seqno;
844 }
845
846 void zebra_end_trans (ZebraHandle zh)
847 {
848     char val;
849     int seqno;
850     const char *rval;
851
852     zh->trans_no--;
853     if (zh->trans_no != 0)
854         return;
855
856     yaz_log (LOG_LOG, "zebra_end_trans");
857     rval = res_get (zh->service->res, "shadow");
858
859     zebra_flush_reg (zh);
860
861     zebra_register_deactivate (zh);
862
863     zebra_get_state (&val, &seqno);
864     if (val != 'd')
865     {
866         BFiles bfs = bfs_create (res_get (zh->service->res, "shadow"));
867         bf_commitClean (bfs, rval);
868         bfs_destroy (bfs);
869     }
870     if (!rval)
871         seqno++;
872     zebra_set_state ('o', seqno);
873
874     zebra_unlock (zh->lock_shadow);
875     zebra_unlock (zh->lock_normal);
876
877 #if HAVE_SYS_TIMES_H
878     times (&zh->tms2);
879     logf (LOG_LOG, "user/system: %ld/%ld",
880                     (long) (zh->tms2.tms_utime - zh->tms1.tms_utime),
881                     (long) (zh->tms2.tms_stime - zh->tms1.tms_stime));
882
883 #endif
884 }
885
886 void zebra_repository_update (ZebraHandle zh)
887 {
888     zebra_begin_trans (zh);
889     logf (LOG_LOG, "updating %s", zh->rGroup.path);
890     repositoryUpdate (zh);    
891     zebra_end_trans (zh);
892 }
893
894 void zebra_repository_delete (ZebraHandle zh)
895 {
896     logf (LOG_LOG, "deleting %s", zh->rGroup.path);
897     repositoryDelete (zh);
898 }
899
900 void zebra_repository_show (ZebraHandle zh)
901 {
902     repositoryShow (zh);
903 }
904
905 void zebra_commit (ZebraHandle zh)
906 {
907     int seqno;
908     char val;
909     const char *rval = res_get (zh->service->res, "shadow");
910     BFiles bfs;
911
912     if (!rval)
913     {
914         logf (LOG_WARN, "Cannot perform commit");
915         logf (LOG_WARN, "No shadow area defined");
916         return;
917     }
918
919     zebra_lock_w (zh->lock_normal);
920     zebra_lock_r (zh->lock_shadow);
921
922     bfs = bfs_create (res_get (zh->service->res, "register"));
923
924     zebra_get_state (&val, &seqno);
925
926     if (rval && *rval)
927         bf_cache (bfs, rval);
928     if (bf_commitExists (bfs))
929     {
930         zebra_set_state ('c', seqno);
931
932         logf (LOG_LOG, "commit start");
933         bf_commitExec (bfs);
934 #ifndef WIN32
935         sync ();
936 #endif
937         logf (LOG_LOG, "commit clean");
938         bf_commitClean (bfs, rval);
939         seqno++;
940         zebra_set_state ('o', seqno);
941     }
942     else
943     {
944         logf (LOG_LOG, "nothing to commit");
945     }
946     bfs_destroy (bfs);
947
948     zebra_unlock (zh->lock_shadow);
949     zebra_unlock (zh->lock_normal);
950 }
951
952 void zebra_init (ZebraHandle zh)
953 {
954     const char *rval = res_get (zh->service->res, "shadow");
955     BFiles bfs = 0;
956
957     bfs = bfs_create (res_get (zh->service->res, "register"));
958     if (rval && *rval)
959         bf_cache (bfs, rval);
960     
961     bf_reset (bfs);
962     bfs_destroy (bfs);
963     zebra_set_state ('o', 0);
964 }
965
966 void zebra_compact (ZebraHandle zh)
967 {
968     BFiles bfs = bfs_create (res_get (zh->service->res, "register"));
969     inv_compact (bfs);
970     bfs_destroy (bfs);
971 }
972
973 int zebra_record_insert (ZebraHandle zh, const char *buf, int len)
974 {
975     int sysno = 0;
976     zebra_begin_trans (zh);
977     extract_rec_in_mem (zh, "grs.sgml",
978                         buf, len,
979                         "Default",  /* database */
980                         0 /* delete_flag */,
981                         0 /* test_mode */,
982                         &sysno /* sysno */,
983                         1 /* store_keys */,
984                         1 /* store_data */,
985                         0 /* match criteria */);
986     zebra_end_trans (zh);
987     return sysno;
988 }