First work on threaded version.
[idzebra-moved-to-github.git] / index / retrieve.c
1 /*
2  * Copyright (C) 1995-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: retrieve.c,v $
7  * Revision 1.12  2000-03-15 15:00:30  adam
8  * First work on threaded version.
9  *
10  * Revision 1.11  1999/10/29 10:00:00  adam
11  * Fixed minor bug where database name wasn't set in zebra_record_fetch.
12  *
13  * Revision 1.10  1999/05/26 07:49:13  adam
14  * C++ compilation.
15  *
16  * Revision 1.9  1999/05/20 12:57:18  adam
17  * Implemented TCL filter. Updated recctrl system.
18  *
19  * Revision 1.8  1999/03/09 16:27:49  adam
20  * More work on SDRKit integration.
21  *
22  * Revision 1.7  1999/03/02 16:15:43  quinn
23  * Added "tagsysno" and "tagrank" directives to zebra.cfg.
24  *
25  * Revision 1.6  1999/02/18 15:01:25  adam
26  * Minor changes.
27  *
28  * Revision 1.5  1999/02/17 11:29:56  adam
29  * Fixed in record_fetch. Minor updates to API.
30  *
31  * Revision 1.4  1999/02/02 14:51:07  adam
32  * Updated WIN32 code specific sections. Changed header.
33  *
34  * Revision 1.3  1998/10/28 10:54:40  adam
35  * SDRKit integration.
36  *
37  * Revision 1.2  1998/10/16 08:14:33  adam
38  * Updated record control system.
39  *
40  * Revision 1.1  1998/03/05 08:45:13  adam
41  * New result set model and modular ranking system. Moved towards
42  * descent server API. System information stored as "SGML" records.
43  *
44  */
45
46 #include <stdio.h>
47 #include <assert.h>
48
49 #include <fcntl.h>
50 #ifdef WIN32
51 #include <io.h>
52 #include <process.h>
53 #else
54 #include <unistd.h>
55 #endif
56
57 #include <recctrl.h>
58 #include "zserver.h"
59
60 #ifndef ZEBRASDR
61 #define ZEBRASDR 0
62 #endif
63
64 #if ZEBRASDR
65 #include "zebrasdr.h"
66 #endif
67
68 struct fetch_control {
69     int record_offset;
70     int record_int_pos;
71     char *record_int_buf;
72     int record_int_len;
73     int fd;
74 };
75
76 static int record_ext_read (void *fh, char *buf, size_t count)
77 {
78     struct fetch_control *fc = (struct fetch_control *) fh;
79     return read (fc->fd, buf, count);
80 }
81
82 static off_t record_ext_seek (void *fh, off_t offset)
83 {
84     struct fetch_control *fc = (struct fetch_control *) fh;
85     return lseek (fc->fd, offset + fc->record_offset, SEEK_SET);
86 }
87
88 static off_t record_ext_tell (void *fh)
89 {
90     struct fetch_control *fc = (struct fetch_control *) fh;
91     return lseek (fc->fd, 0, SEEK_CUR) - fc->record_offset;
92 }
93
94 static off_t record_int_seek (void *fh, off_t offset)
95 {
96     struct fetch_control *fc = (struct fetch_control *) fh;
97     return (off_t) (fc->record_int_pos = offset);
98 }
99
100 static off_t record_int_tell (void *fh)
101 {
102     struct fetch_control *fc = (struct fetch_control *) fh;
103     return (off_t) fc->record_int_pos;
104 }
105
106 static int record_int_read (void *fh, char *buf, size_t count)
107 {
108     struct fetch_control *fc = (struct fetch_control *) fh;
109     int l = fc->record_int_len - fc->record_int_pos;
110     if (l <= 0)
111         return 0;
112     l = (l < (int) count) ? l : count;
113     memcpy (buf, fc->record_int_buf + fc->record_int_pos, l);
114     fc->record_int_pos += l;
115     return l;
116 }
117
118 int zebra_record_fetch (ZebraHandle zh, int sysno, int score, ODR stream,
119                         oid_value input_format, Z_RecordComposition *comp,
120                         oid_value *output_format, char **rec_bufp,
121                         int *rec_lenp, char **basenamep)
122 {
123     Record rec;
124     char *fname, *file_type, *basename;
125     RecType rt;
126     struct recRetrieveCtrl retrieveCtrl;
127     char subType[128];
128     struct fetch_control fc;
129     RecordAttr *recordAttr;
130     void *clientData;
131
132     rec = rec_get (zh->service->records, sysno);
133     if (!rec)
134     {
135         logf (LOG_DEBUG, "rec_get fail on sysno=%d", sysno);
136         *basenamep = 0;
137         return 14;
138     }
139     recordAttr = rec_init_attr (zh->service->zei, rec);
140
141     file_type = rec->info[recInfo_fileType];
142     fname = rec->info[recInfo_filename];
143     basename = rec->info[recInfo_databaseName];
144     *basenamep = (char *) odr_malloc (stream, strlen(basename)+1);
145     strcpy (*basenamep, basename);
146
147     if (!(rt = recType_byName (zh->service->recTypes,
148                                file_type, subType, &clientData)))
149     {
150         logf (LOG_WARN, "Retrieve: Cannot handle type %s",  file_type);
151         return 14;
152     }
153     logf (LOG_DEBUG, "retrieve localno=%d score=%d", sysno, score);
154     retrieveCtrl.fh = &fc;
155     fc.fd = -1;
156     if (rec->size[recInfo_storeData] > 0)
157     {
158         retrieveCtrl.readf = record_int_read;
159         retrieveCtrl.seekf = record_int_seek;
160         retrieveCtrl.tellf = record_int_tell;
161         fc.record_int_len = rec->size[recInfo_storeData];
162         fc.record_int_buf = rec->info[recInfo_storeData];
163         fc.record_int_pos = 0;
164         logf (LOG_DEBUG, "Internal retrieve. %d bytes", fc.record_int_len);
165     }
166 #if ZEBRASDR
167     else if (*fname == '%')
168     {   
169         ZebraSdrHandle h;
170         int segment = 0, r;
171         char *cp, xname[128];
172         unsigned char *buf;
173
174         logf (LOG_DEBUG, "SDR");
175         strcpy (xname, fname+1);
176         if ((cp = strrchr (xname, '.')))
177         {
178             *cp++ = 0;
179             segment = atoi(cp);
180         }
181         h = zebraSdr_open (xname);
182         if (!h)
183         {
184             logf (LOG_WARN, "sdr open %s", xname);
185             return 0;
186         }
187         if (zebraSdr_segment (h, &segment) < 0)
188         {
189             logf (LOG_WARN, "zebraSdr_segment fail segment=%d",
190                 segment);
191             rec_rm (&rec);
192             return 14;
193         }    
194         r = zebraSdr_read (h, &buf);
195         if (r < 1)
196         {
197             logf (LOG_WARN, "zebraSdr_read fail segment=%d",
198                 segment);
199             rec_rm (&rec);
200             return 14;
201         }
202         zebraSdr_close (h);
203
204         fc.record_int_len = recordAttr->recordSize;
205         fc.record_int_buf = buf + recordAttr->recordOffset;
206         fc.record_int_pos = 0;
207
208         logf (LOG_LOG, "segment = %d len=%d off=%d",
209             segment,
210             recordAttr->recordSize,
211             recordAttr->recordOffset);
212         if (fc.record_int_len > 180)
213         {
214             logf (LOG_LOG, "%.70s", fc.record_int_buf);
215             logf (LOG_LOG, "%.70s", fc.record_int_buf +
216                 (fc.record_int_len - 70));
217         }
218         else
219             logf (LOG_LOG, "%.*s",
220                 fc.record_int_len, fc.record_int_buf);
221
222         /* the following two lines makes rec_rm delete buf */
223         rec->size[recInfo_storeData] = r;
224         rec->info[recInfo_storeData] = buf;
225
226         retrieveCtrl.readf = record_int_read;
227         retrieveCtrl.seekf = record_int_seek;
228         retrieveCtrl.tellf = record_int_tell;
229     }
230 #endif
231     else
232     {
233         if ((fc.fd = open (fname, O_BINARY|O_RDONLY)) == -1)
234         {
235             logf (LOG_WARN|LOG_ERRNO, "Retrieve fail; missing file: %s",
236                   fname);
237             rec_rm (&rec);
238             return 14;
239         }
240         fc.record_offset = recordAttr->recordOffset;
241
242         retrieveCtrl.readf = record_ext_read;
243         retrieveCtrl.seekf = record_ext_seek;
244         retrieveCtrl.tellf = record_ext_tell;
245
246         record_ext_seek (retrieveCtrl.fh, 0);
247     }
248     retrieveCtrl.subType = subType;
249     retrieveCtrl.localno = sysno;
250     retrieveCtrl.score = score;
251     retrieveCtrl.recordSize = recordAttr->recordSize;
252     retrieveCtrl.odr = stream;
253     retrieveCtrl.input_format = retrieveCtrl.output_format = input_format;
254     retrieveCtrl.comp = comp;
255     retrieveCtrl.diagnostic = 0;
256     retrieveCtrl.dh = zh->service->dh;
257     retrieveCtrl.res = zh->service->res;
258     (*rt->retrieve)(clientData, &retrieveCtrl);
259     *output_format = retrieveCtrl.output_format;
260     *rec_bufp = (char *) retrieveCtrl.rec_buf;
261     *rec_lenp = retrieveCtrl.rec_len;
262     if (fc.fd != -1)
263         close (fc.fd);
264     rec_rm (&rec);
265
266     return retrieveCtrl.diagnostic;
267 }