Added referenceId handling for server.
[yazpp-moved-to-github.git] / src / yaz-z-server-sr.cpp
1 /*
2  * Copyright (c) 2000-2001, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Log: yaz-z-server-sr.cpp,v $
6  * Revision 1.3  2001-04-25 18:59:30  adam
7  * Added referenceId handling for server.
8  *
9  * Revision 1.2  2001/04/04 14:02:49  adam
10  * URSULA / Z-ruth service.
11  *
12  * Revision 1.1  2001/03/27 15:02:14  adam
13  * New server facility scheme.
14  *
15  */
16
17 #include <yaz/log.h>
18 #include <yaz++/yaz-z-server.h>
19
20 Z_Records *Yaz_Facility_Retrieval::pack_records (Yaz_Z_Server *s,
21                                                  const char *resultSetName,
22                                                  int start, int xnum,
23                                                  Z_RecordComposition *comp,
24                                                  int *next, int *pres,
25                                                  int *format)
26 {
27     int recno, total_length = 0, toget = xnum, dumped_records = 0;
28     Z_Records *records =
29         (Z_Records *) odr_malloc (odr_encode(), sizeof(*records));
30     Z_NamePlusRecordList *reclist =
31         (Z_NamePlusRecordList *) odr_malloc (odr_encode(), sizeof(*reclist));
32     Z_NamePlusRecord **list =
33         (Z_NamePlusRecord **) odr_malloc (odr_encode(), sizeof(*list) * toget);
34
35     records->which = Z_Records_DBOSD;
36     records->u.databaseOrSurDiagnostics = reclist;
37     reclist->num_records = 0;
38     reclist->records = list;
39     *pres = Z_PRES_SUCCESS;
40     *next = 0;
41
42     yaz_log(LOG_LOG, "Request to pack %d+%d", start, toget);
43     yaz_log(LOG_LOG, "pms=%d, mrs=%d", m_preferredMessageSize,
44             m_maximumRecordSize);
45     for (recno = start; reclist->num_records < toget; recno++)
46     {
47         Z_NamePlusRecord *this_rec =
48             (Z_NamePlusRecord *) odr_malloc (odr_encode(), sizeof(*this_rec));
49         this_rec->databaseName = 0;
50         this_rec->which = Z_NamePlusRecord_databaseRecord;
51         this_rec->u.databaseRecord = 0;
52
53         int this_length = 0;
54
55         sr_record (resultSetName, recno, format, comp, this_rec, records);
56
57         if (records->which != Z_Records_DBOSD)
58         {
59             *pres = Z_PRES_FAILURE;
60             return records;
61         }
62
63         if (this_rec->which == Z_NamePlusRecord_databaseRecord &&
64             this_rec->u.databaseRecord == 0)
65         {   // handler did not return a record..
66             create_surrogateDiagnostics(odr_encode(), this_rec, 0, 14, 0);
67         }
68         /*
69          * we get the number of bytes allocated on the stream before any
70          * allocation done by the backend - this should give us a reasonable
71          * idea of the total size of the data so far.
72          */
73         total_length = odr_total(odr_encode()) - dumped_records;
74         this_length = odr_total(odr_encode()) - total_length;
75         yaz_log(LOG_LOG, "  fetched record, len=%d, total=%d",
76                 this_length, total_length);
77         if (this_length + total_length > m_preferredMessageSize)
78         {
79             /* record is small enough, really */
80             if (this_length <= m_preferredMessageSize)
81             {
82                 yaz_log(LOG_LOG, "  Dropped last normal-sized record");
83                 *pres = Z_PRES_PARTIAL_2;
84                 break;
85             }
86             if (this_length >= m_maximumRecordSize)
87             {   /* too big entirely */
88                 yaz_log(LOG_LOG, "Record > maxrcdsz");
89                 reclist->records[reclist->num_records] = this_rec;
90                 create_surrogateDiagnostics(odr_encode(), this_rec,
91                                             this_rec->databaseName, 17, 0);
92                 reclist->num_records++;
93                 *next = recno + 1;
94                 dumped_records += this_length;
95                 continue;
96             }
97             else /* record can only be fetched by itself */
98             {
99                 yaz_log(LOG_LOG, "  Record > prefmsgsz");
100                 if (toget > 1)
101                 {
102                     yaz_log(LOG_DEBUG, "  Dropped it");
103                     reclist->records[reclist->num_records] = this_rec;
104                     create_surrogateDiagnostics(odr_encode(), this_rec,
105                                                 this_rec->databaseName,
106                                                 16, 0);
107                     reclist->num_records++;
108                     // *next = freq.last_in_set ? 0 : recno + 1;
109                     *next = recno + 1;
110                     dumped_records += this_length;
111                     continue;
112                 }
113             }
114         }
115         reclist->records[reclist->num_records] = this_rec;
116         reclist->num_records++;
117         *next = recno + 1;
118     }
119     return records;
120 }
121
122 void Yaz_Facility_Retrieval::fetch_via_piggyback (Yaz_Z_Server *s,
123                                                   Z_SearchRequest *req,
124                                                   Z_SearchResponse *res)
125 {
126     bool_t *sr = (bool_t *)odr_malloc (odr_encode(), sizeof(*sr));
127     *sr = 1;
128     
129     int toget = 0;
130     
131     Z_RecordComposition comp, *compp = 0;
132     int hits = *res->resultCount;
133     
134     int *nulint = (int *)odr_malloc (odr_encode(), sizeof(*nulint));
135     *nulint = 0;
136     
137     comp.which = Z_RecordComp_simple;
138     /* how many records does the user agent want, then? */
139     if (hits <= *req->smallSetUpperBound)
140     {
141         toget = hits;
142         if ((comp.u.simple = req->smallSetElementSetNames))
143             compp = &comp;
144     }
145     else if (hits < *req->largeSetLowerBound)
146     {
147         toget = *req->mediumSetPresentNumber;
148         if (toget > hits)
149             toget = hits;
150         if ((comp.u.simple = req->mediumSetElementSetNames))
151             compp = &comp;
152     }
153     
154     if (toget && !res->records)
155     {
156         res->presentStatus = (int *) odr_malloc (odr_encode(), sizeof(int));
157         *res->presentStatus = Z_PRES_SUCCESS;
158         res->records =
159             pack_records(s, req->resultSetName, 1, toget, compp, 
160                          res->nextResultSetPosition,
161                          res->presentStatus,
162                          req->preferredRecordSyntax);
163         if (!res->records)
164             return;
165         if (res->records->which == Z_Records_DBOSD)
166             *res->numberOfRecordsReturned =
167                 res->records->u.databaseOrSurDiagnostics->num_records;
168         res->searchStatus = sr;
169         res->resultSetStatus = 0;
170     }
171     else
172     {
173         if (hits)
174             *res->nextResultSetPosition = 1;
175         res->numberOfRecordsReturned = nulint;
176         res->searchStatus = sr;
177         res->resultSetStatus = 0;
178         res->presentStatus = 0;
179     }
180 }
181
182 void Yaz_Facility_Retrieval::fetch_via_present (Yaz_Z_Server *s,
183                                                 Z_PresentRequest *req,
184                                                 Z_PresentResponse *res)
185 {
186     res->records =
187         pack_records (s, req->resultSetId,*req->resultSetStartPoint, 
188                       *req->numberOfRecordsRequested,
189                       req->recordComposition,
190                       res->nextResultSetPosition,
191                       res->presentStatus,
192                       req->preferredRecordSyntax);
193     if (res->records->which == Z_Records_DBOSD)
194         *res->numberOfRecordsReturned =
195             res->records->u.databaseOrSurDiagnostics->num_records;
196 }
197
198 int Yaz_Facility_Retrieval::init(Yaz_Z_Server *s, Z_InitRequest *initRequest,
199                                  Z_InitResponse *initResponse)
200 {
201     Z_Options *req = initRequest->options;
202     Z_Options *res = initResponse->options;
203     
204     if (ODR_MASK_GET(req, Z_Options_search))
205         ODR_MASK_SET(res, Z_Options_search);
206     if (ODR_MASK_GET(req, Z_Options_present))
207         ODR_MASK_SET(res, Z_Options_present);
208     m_preferredMessageSize = *initRequest->preferredMessageSize;
209     m_maximumRecordSize = *initRequest->maximumRecordSize;
210     return sr_init (initRequest, initResponse);
211 }
212
213 ODR Yaz_Facility_Retrieval::odr_encode()
214 {
215     return m_odr_encode;
216 }
217
218 ODR Yaz_Facility_Retrieval::odr_decode()
219 {
220     return m_odr_decode;
221 }
222
223 int Yaz_Facility_Retrieval::recv(Yaz_Z_Server *s, Z_APDU *apdu_request)
224 {   
225     Z_APDU *apdu_response;
226     m_odr_encode = s->odr_encode();
227     m_odr_decode = s->odr_decode();
228     switch (apdu_request->which)
229     {
230     case Z_APDU_searchRequest:
231         yaz_log (LOG_LOG, "got SearchRequest p=%p", this);
232         apdu_response = s->create_Z_PDU(Z_APDU_searchResponse);
233         s->transfer_referenceId(apdu_request, apdu_response);
234         sr_search (apdu_request->u.searchRequest,
235                        apdu_response->u.searchResponse);
236         if (!apdu_response->u.searchResponse->records)
237         {
238             fetch_via_piggyback(s, apdu_request->u.searchRequest,
239                                 apdu_response->u.searchResponse);
240         }
241         s->send_Z_PDU(apdu_response);
242         return 1;
243     case Z_APDU_presentRequest:
244         yaz_log (LOG_LOG, "got PresentRequest p=%p", this);
245         apdu_response = s->create_Z_PDU(Z_APDU_presentResponse);
246         s->transfer_referenceId(apdu_request, apdu_response);
247         sr_present (apdu_request->u.presentRequest,
248                     apdu_response->u.presentResponse);
249         if (!apdu_response->u.presentResponse->records)
250             fetch_via_present(s, apdu_request->u.presentRequest,
251                               apdu_response->u.presentResponse);
252         s->send_Z_PDU(apdu_response);
253         return 1;
254     }
255     return 0;
256 }