Work on update while servers are running. Three lock files introduced.
[idzebra-moved-to-github.git] / index / zserver.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: zserver.c,v $
7  * Revision 1.31  1995-12-08 16:22:56  adam
8  * Work on update while servers are running. Three lock files introduced.
9  * The servers reload their registers when necessary, but they don't
10  * reestablish result sets yet.
11  *
12  * Revision 1.30  1995/12/07  17:38:48  adam
13  * Work locking mechanisms for concurrent updates/commit.
14  *
15  * Revision 1.29  1995/12/04  14:22:32  adam
16  * Extra arg to recType_byName.
17  * Started work on new regular expression parsed input to
18  * structured records.
19  *
20  * Revision 1.28  1995/11/28  09:09:48  adam
21  * Zebra config renamed.
22  * Use setting 'recordId' to identify record now.
23  * Bug fix in recindex.c: rec_release_blocks was invokeded even
24  * though the blocks were already released.
25  * File traversal properly deletes records when needed.
26  *
27  * Revision 1.27  1995/11/27  13:58:54  adam
28  * New option -t. storeStore data implemented in server.
29  *
30  * Revision 1.26  1995/11/25  10:24:07  adam
31  * More record fields - they are enumerated now.
32  * New options: flagStoreData flagStoreKey.
33  *
34  * Revision 1.25  1995/11/21  15:29:13  adam
35  * Config file 'base' read by default by both indexer and server.
36  *
37  * Revision 1.24  1995/11/20  16:59:47  adam
38  * New update method: the 'old' keys are saved for each records.
39  *
40  * Revision 1.23  1995/11/16  17:00:56  adam
41  * Better logging of rpn query.
42  *
43  * Revision 1.22  1995/11/16  15:34:55  adam
44  * Uses new record management system in both indexer and server.
45  *
46  * Revision 1.21  1995/11/01  16:25:52  quinn
47  * *** empty log message ***
48  *
49  * Revision 1.20  1995/10/27  14:00:12  adam
50  * Implemented detection of database availability.
51  *
52  * Revision 1.19  1995/10/17  18:02:11  adam
53  * New feature: databases. Implemented as prefix to words in dictionary.
54  *
55  * Revision 1.18  1995/10/16  14:03:09  quinn
56  * Changes to support element set names and espec1
57  *
58  * Revision 1.17  1995/10/16  09:32:40  adam
59  * More work on relational op.
60  *
61  * Revision 1.16  1995/10/13  12:26:44  adam
62  * Optimization of truncation.
63  *
64  * Revision 1.15  1995/10/12  12:40:55  adam
65  * Bug fixes in rpn_prox.
66  *
67  * Revision 1.14  1995/10/09  16:18:37  adam
68  * Function dict_lookup_grep got extra client data parameter.
69  *
70  * Revision 1.13  1995/10/06  14:38:00  adam
71  * New result set method: r_score.
72  * Local no (sysno) and score is transferred to retrieveCtrl.
73  *
74  * Revision 1.12  1995/10/06  13:52:06  adam
75  * Bug fixes. Handler may abort further scanning.
76  *
77  * Revision 1.11  1995/10/06  10:43:57  adam
78  * Scan added. 'occurrences' in scan entries not set yet.
79  *
80  * Revision 1.10  1995/10/02  16:43:32  quinn
81  * Set default resulting record type in fetch.
82  *
83  * Revision 1.9  1995/10/02  15:18:52  adam
84  * New member in recRetrieveCtrl: diagnostic.
85  *
86  * Revision 1.8  1995/09/28  09:19:47  adam
87  * xfree/xmalloc used everywhere.
88  * Extract/retrieve method seems to work for text records.
89  *
90  * Revision 1.7  1995/09/27  16:17:32  adam
91  * More work on retrieve.
92  *
93  * Revision 1.6  1995/09/08  08:53:22  adam
94  * Record buffer maintained in server_info.
95  *
96  * Revision 1.5  1995/09/06  16:11:18  adam
97  * Option: only one word key per file.
98  *
99  * Revision 1.4  1995/09/06  10:33:04  adam
100  * More work on present. Some log messages removed.
101  *
102  * Revision 1.3  1995/09/05  15:28:40  adam
103  * More work on search engine.
104  *
105  * Revision 1.2  1995/09/04  12:33:43  adam
106  * Various cleanup. YAZ util used instead.
107  *
108  * Revision 1.1  1995/09/04  09:10:41  adam
109  * More work on index add/del/update.
110  * Merge sort implemented.
111  * Initial work on z39 server.
112  *
113  */
114 #include <stdio.h>
115 #include <assert.h>
116 #include <unistd.h>
117 #include <fcntl.h>
118
119 #include <common.h>
120 #include <data1.h>
121 #include <recctrl.h>
122 #include <dmalloc.h>
123 #include "zserver.h"
124
125 ZServerInfo server_info;
126
127 static int register_lock (ZServerInfo *zi)
128 {
129     time_t lastChange;
130     int state = zebraServerLockGetState(&lastChange);
131
132     switch (state)
133     {
134     case 'c':
135         state = 1;
136         break;
137     default:
138         state = 0;
139     }
140     zebraServerLock (state);
141     if (zi->registerState == state)
142     {
143         if (zi->registerChange >= lastChange)
144             return 0;
145         logf (LOG_LOG, "Register completely updated since last access");
146     }
147     else if (zi->registerState == -1)
148         logf (LOG_LOG, "Reading register using state %d pid=%ld", state,
149               (long) getpid());
150     else
151         logf (LOG_LOG, "Register has changed state from %d to %d",
152               zi->registerState, state);
153     zi->registerChange = lastChange;
154     if (zi->records)
155     {
156         dict_close (zi->wordDict);
157         is_close (zi->wordIsam);
158         rec_close (&zi->records);
159     }
160     bf_cache (state);
161     zi->registerState = state;
162     zi->records = rec_open (0);
163     if (!(zi->wordDict = dict_open (FNAME_WORD_DICT, 40, 0)))
164         return -1;
165     if (!(zi->wordIsam = is_open (FNAME_WORD_ISAM, key_compare, 0,
166                                   sizeof (struct it_key))))
167         return -1;
168     return 0;
169 }
170
171 static int register_unlock (ZServerInfo *zi)
172 {
173     if (zi->registerState != -1)
174         zebraServerUnlock (zi->registerState);
175 }
176
177 bend_initresult *bend_init (bend_initrequest *q)
178 {
179     static bend_initresult r;
180     static char *name = "zserver";
181
182     r.errcode = 0;
183     r.errstring = 0;
184     r.handle = name;
185
186     logf (LOG_DEBUG, "bend_init");
187
188     if (!common_resource)
189     {
190         struct statserv_options_block *sob;
191
192         sob = statserv_getcontrol ();
193         logf (LOG_LOG, "Reading resources from %s", sob->configname);
194         if (!(common_resource = res_open (sob->configname)))
195         {
196             logf (LOG_FATAL, "Cannot open resource `%s'", sob->configname);
197             exit (1);
198         }
199     }
200     data1_tabpath = res_get(common_resource, "profilePath");
201     server_info.sets = NULL;
202     server_info.registerState = -1;  /* trigger open of registers! */
203     server_info.registerChange = 0;
204
205     server_info.records = NULL;
206     server_info.wordDict = NULL;
207     server_info.wordIsam = NULL;
208     server_info.odr = odr_createmem (ODR_ENCODE);
209     return &r;
210 }
211
212 bend_searchresult *bend_search (void *handle, bend_searchrequest *q, int *fd)
213 {
214     static bend_searchresult r;
215
216     r.errcode = 0;
217     r.errstring = 0;
218     r.hits = 0;
219
220     register_lock (&server_info);
221     odr_reset (server_info.odr);
222     server_info.errCode = 0;
223     server_info.errString = NULL;
224
225     logf (LOG_LOG, "ResultSet '%s'", q->setname);
226     switch (q->query->which)
227     {
228     case Z_Query_type_1:
229         r.errcode = rpn_search (&server_info, q->query->u.type_1,
230                                 q->num_bases, q->basenames, q->setname,
231                                 &r.hits);
232         r.errstring = server_info.errString;
233         break;
234     default:
235         r.errcode = 107;
236     }
237     register_unlock (&server_info);
238     return &r;
239 }
240
241 static int record_ext_read (int fd, char *buf, size_t count)
242 {
243     return read (fd, buf, count);
244 }
245
246 static int record_int_pos;
247 static char *record_int_buf;
248 static int record_int_len;
249
250 static int record_int_read (int fd, char *buf, size_t count)
251 {
252     int l = record_int_len - record_int_pos;
253     if (l <= 0)
254         return 0;
255     l = (l < count) ? l : count;
256     memcpy (buf, record_int_buf + record_int_pos, l);
257     record_int_pos += l;
258     return l;
259 }
260
261 static int record_fetch (ZServerInfo *zi, int sysno, int score, ODR stream,
262                           oid_value input_format, Z_RecordComposition *comp,
263                           oid_value *output_format, char **rec_bufp,
264                           int *rec_lenp)
265 {
266     Record rec;
267     char *fname, *file_type;
268     RecType rt;
269     struct recRetrieveCtrl retrieveCtrl;
270     char subType[128];
271
272     rec = rec_get (zi->records, sysno);
273     file_type = rec->info[recInfo_fileType];
274     fname = rec->info[recInfo_filename];
275
276     if (!(rt = recType_byName (file_type, subType)))
277     {
278         logf (LOG_FATAL|LOG_ERRNO, "Retrieve: Cannot handle type %s", 
279               file_type);
280         exit (1);
281     }
282     logf (LOG_DEBUG, "retrieve localno=%d score=%d", sysno, score);
283     if (rec->size[recInfo_storeData] > 0)
284     {
285         retrieveCtrl.readf = record_int_read;
286         record_int_len = rec->size[recInfo_storeData];
287         record_int_buf = rec->info[recInfo_storeData];
288         record_int_pos = 0;
289         logf (LOG_DEBUG, "Internal retrieve. %d bytes", record_int_len);
290     }
291     else 
292     {
293         if ((retrieveCtrl.fd = open (fname, O_RDONLY)) == -1)
294         {
295             char *msg = "Record doesn't exist";
296             logf (LOG_WARN|LOG_ERRNO, "Retrieve: Open record file %s", fname);
297             *output_format = VAL_SUTRS;
298             *rec_bufp = msg;
299             *rec_lenp = strlen (msg);
300             rec_rm (&rec);
301             return 0;     /* or 14: System error in presenting records */
302         }
303         retrieveCtrl.readf = record_ext_read;
304     }
305     retrieveCtrl.subType = subType;
306     retrieveCtrl.localno = sysno;
307     retrieveCtrl.score = score;
308     retrieveCtrl.odr = stream;
309     retrieveCtrl.input_format = retrieveCtrl.output_format = input_format;
310     retrieveCtrl.comp = comp;
311     retrieveCtrl.diagnostic = 0;
312     (*rt->retrieve)(&retrieveCtrl);
313     *output_format = retrieveCtrl.output_format;
314     *rec_bufp = retrieveCtrl.rec_buf;
315     *rec_lenp = retrieveCtrl.rec_len;
316     close (retrieveCtrl.fd);
317     rec_rm (&rec);
318
319     return retrieveCtrl.diagnostic;
320 }
321
322 bend_fetchresult *bend_fetch (void *handle, bend_fetchrequest *q, int *num)
323 {
324     static bend_fetchresult r;
325     int positions[2];
326     ZServerSetSysno *records;
327
328     register_lock (&server_info);
329
330     r.errstring = 0;
331     r.last_in_set = 0;
332     r.basename = "base";
333
334     odr_reset (server_info.odr);
335     server_info.errCode = 0;
336
337     positions[0] = q->number;
338     records = resultSetSysnoGet (&server_info, q->setname, 1, positions);
339     if (!records)
340     {
341         logf (LOG_DEBUG, "resultSetRecordGet, error");
342         r.errcode = 13;
343         register_unlock (&server_info);
344         return &r;
345     }
346     if (!records[0].sysno)
347     {
348         r.errcode = 13;
349         logf (LOG_DEBUG, "Out of range. pos=%d", q->number);
350         register_unlock (&server_info);
351         return &r;
352     }
353     r.errcode = record_fetch (&server_info, records[0].sysno,
354                               records[0].score, q->stream, q->format,
355                               q->comp, &r.format, &r.record, &r.len);
356     resultSetSysnoDel (&server_info, records, 1);
357     register_unlock (&server_info);
358     return &r;
359 }
360
361 bend_deleteresult *bend_delete (void *handle, bend_deleterequest *q, int *num)
362 {
363     register_lock (&server_info);
364     register_unlock (&server_info);
365     return 0;
366 }
367
368 bend_scanresult *bend_scan (void *handle, bend_scanrequest *q, int *num)
369 {
370     static bend_scanresult r;
371     int status;
372
373     register_lock (&server_info);
374     odr_reset (server_info.odr);
375     server_info.errCode = 0;
376     server_info.errString = 0;
377
378     r.term_position = q->term_position;
379     r.num_entries = q->num_entries;
380     r.errcode = rpn_scan (&server_info, q->term,
381                           q->num_bases, q->basenames,
382                           &r.term_position,
383                           &r.num_entries, &r.entries, &status);
384     r.errstring = server_info.errString;
385     r.status = status;
386     register_unlock (&server_info);
387     return &r;
388 }
389
390 void bend_close (void *handle)
391 {
392     if (server_info.records)
393     {
394         dict_close (server_info.wordDict);
395         is_close (server_info.wordIsam);
396         rec_close (&server_info.records);
397         register_unlock (&server_info);
398     }
399     return;
400 }
401
402 int main (int argc, char **argv)
403 {
404     struct statserv_options_block *sob;
405
406     sob = statserv_getcontrol ();
407     strcpy (sob->configname, FNAME_CONFIG);
408     statserv_setcontrol (sob);
409
410     return statserv_main (argc, argv);
411 }