metaproxy 1.22.4
filter_session_shared.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20
21#include <metaproxy/filter.hpp>
22#include <metaproxy/package.hpp>
23
24#include <boost/thread/mutex.hpp>
25#include <boost/thread/condition.hpp>
26#include <boost/thread/thread.hpp>
27#include <boost/thread/xtime.hpp>
28#include <boost/shared_ptr.hpp>
29#include <boost/format.hpp>
30
31#include <metaproxy/util.hpp>
33
34#include <yaz/copy_types.h>
35#include <yaz/log.h>
36#include <yaz/zgdu.h>
37#include <yaz/otherinfo.h>
38#include <yaz/diagbib1.h>
39#include <yazpp/z-query.h>
40#include <yazpp/record-cache.h>
41#include <map>
42#include <iostream>
43#include <time.h>
44#include <limits.h>
45
46namespace mp = metaproxy_1;
47namespace yf = metaproxy_1::filter;
48
49namespace metaproxy_1 {
50
51 namespace filter {
52 // key for session.. We'll only share sessions with same InitKey
54 public:
55 bool operator < (const SessionShared::InitKey &k) const;
56 InitKey(Z_InitRequest *req);
57 InitKey(const InitKey &);
58 ~InitKey();
59 private:
64 ODR m_odr;
65 };
66 // worker thread .. for expiry of sessions
68 public:
70 void operator() (void);
71 private:
73 };
74 // backend result set
76 public:
77 std::string m_result_set_id;
80 yazpp_1::Yaz_Z_Query m_query;
82 void timestamp();
83 yazpp_1::RecordCache m_record_cache;
84
85 Z_OtherInformation *additionalSearchInfoRequest;
86 Z_OtherInformation *additionalSearchInfoResponse;
89 const std::string &result_set_id,
90 const Databases &databases,
91 const yazpp_1::Yaz_Z_Query &query,
92 Z_OtherInformation *additionalSearchInfoRequest);
94 bool search(
95 Package &frontend_package,
96 Package &search_package,
97 const Z_APDU *apdu_req,
98 const BackendInstancePtr bp,
99 Z_Records **z_records);
100 };
101 // backend connection instance
103 friend class Rep;
104 friend class BackendClass;
105 friend class BackendSet;
106 public:
107 mp::Session m_session;
113 mp::Package * m_close_package;
115 void timestamp();
116 };
117 // backends of some class (all with same InitKey)
118 class SessionShared::BackendClass : boost::noncopyable {
119 friend class Rep;
120 friend struct Frontend;
123 BackendInstancePtr create_backend(const Package &package,
124 int &code, std::string &addinfo);
126 BackendInstancePtr get_backend(const Package &package,
127 int &code, std::string &addinfo);
130 bool expire_instances();
131 yazpp_1::GDU m_init_request;
132 yazpp_1::GDU m_init_response;
134 boost::condition m_cond_set_ready;
144 public:
145 BackendClass(const yazpp_1::GDU &init_request,
146 int resultset_ttl,
147 int resultset_max,
148 int session_ttl,
149 Odr_int preferredRecordSize,
150 Odr_int maximumRecordSize);
152 };
153 // frontend result set
156 yazpp_1::Yaz_Z_Query m_query;
157 public:
158 const Databases &get_databases();
159 const yazpp_1::Yaz_Z_Query &get_query();
161 const Databases &databases,
162 const yazpp_1::Yaz_Z_Query &query);
164 };
165 // frontend session
167 Frontend(Rep *rep);
168 ~Frontend();
171 Z_Options m_init_options;
172 void search(Package &package, Z_APDU *apdu);
173 void present(Package &package, Z_APDU *apdu);
174 void scan(Package &package, Z_APDU *apdu);
175
176 int result_set_ref(ODR o,
177 const Databases &databases,
178 Z_RPNStructure *s, std::string &rset);
179 void get_set(mp::Package &package,
180 const Z_APDU *apdu_req,
181 const Databases &databases,
182 yazpp_1::Yaz_Z_Query &query,
183 BackendInstancePtr &found_backend,
184 BackendSetPtr &found_set);
185 void override_set(BackendInstancePtr &found_backend,
186 std::string &result_set_id,
187 const Databases &databases,
188 bool out_of_sessions);
189
193 };
194 // representation
196 friend class SessionShared;
197 friend struct Frontend;
198
199 FrontendPtr get_frontend(Package &package);
200 void release_frontend(Package &package);
201 Rep();
202 public:
203 ~Rep();
204 void expire();
205 private:
206 void expire_classes();
207 void init(Package &package, const Z_GDU *gdu,
208 FrontendPtr frontend);
209 void start();
210 boost::mutex m_mutex;
211 boost::condition m_cond_session_ready;
212 boost::condition m_cond_expire_ready;
213 std::map<mp::Session, FrontendPtr> m_clients;
214
217 boost::thread_group m_thrds;
228 };
229 }
230}
231
233 const Databases &databases,
234 const yazpp_1::Yaz_Z_Query &query)
235 : m_databases(databases), m_query(query)
236{
237}
238
244
245const yazpp_1::Yaz_Z_Query& yf::SessionShared::FrontendSet::get_query()
246{
247 return m_query;
248}
249
264
266{
267 m_odr = odr_createmem(ODR_ENCODE);
268
269 Z_IdAuthentication *t = req->idAuthentication;
270 z_IdAuthentication(m_odr, &t, 1, 0);
272 odr_getbuf(m_odr, &m_idAuthentication_size, 0);
273
274 Z_OtherInformation *o = req->otherInfo;
275 z_OtherInformation(m_odr, &o, 1, 0);
276 m_otherInfo_buf = odr_getbuf(m_odr, &m_otherInfo_size, 0);
277}
278
280{
281 odr_destroy(m_odr);
282}
283
285 const
286{
287 int c;
288 c = mp::util::memcmp2(
291 if (c < 0)
292 return true;
293 else if (c > 0)
294 return false;
295
296 c = mp::util::memcmp2((void*) m_otherInfo_buf, m_otherInfo_size,
297 (void*) k.m_otherInfo_buf, k.m_otherInfo_size);
298 if (c < 0)
299 return true;
300 else if (c > 0)
301 return false;
302 return false;
303}
304
306{
307 boost::mutex::scoped_lock lock(m_mutex_backend_class);
308 m_cond_set_ready.notify_all();
309 b->m_in_use = false;
310}
311
312
314{
315 {
316 boost::mutex::scoped_lock lock(m_mutex_backend_class);
317 BackendInstanceList::iterator it = m_backend_list.begin();
318 for (;;)
319 {
320 if (it == m_backend_list.end())
321 return;
322 if (*it == b)
323 {
324 it = m_backend_list.erase(it);
325 break;
326 }
327 it++;
328 }
329 }
330 mp::odr odr;
331 b->m_close_package->response() = odr.create_close(
332 0, Z_Close_lackOfActivity, 0);
333 b->m_close_package->session().close();
334 b->m_close_package->move();
335}
336
337
340 const mp::Package &frontend_package,
341 int &code, std::string &addinfo)
342{
343 {
344 boost::mutex::scoped_lock lock(m_mutex_backend_class);
345
346 BackendInstanceList::const_iterator it = m_backend_list.begin();
347
348 BackendInstancePtr backend1; // null
349
350 for (; it != m_backend_list.end(); it++)
351 {
352 if (!(*it)->m_in_use)
353 {
354 if (!backend1
355 || (*it)->m_sequence_this < backend1->m_sequence_this)
356 backend1 = *it;
357 }
358 }
359 if (backend1)
360 {
361 use_backend(backend1);
362 return backend1;
363 }
364 }
365 return create_backend(frontend_package, code, addinfo);
366}
367
369{
370 backend->m_in_use = true;
371 backend->m_sequence_this = m_sequence_top++;
372}
373
379
381{
382 if (m_close_package)
383 {
384 mp::odr odr;
385 m_close_package->response() = odr.create_close(
386 0, Z_Close_lackOfActivity, 0);
387 m_close_package->session().close();
388 m_close_package->move();
389 }
390 delete m_close_package;
391}
392
394 const mp::Package &frontend_package,
395 int &code, std::string &addinfo)
396{
399 bp->m_close_package =
400 new mp::Package(bp->m_session, frontend_package.origin());
401 bp->m_close_package->copy_filter(frontend_package);
402
403 Package init_package(bp->m_session, frontend_package.origin());
404
405 init_package.copy_filter(frontend_package);
406
407 yazpp_1::GDU actual_init_request = m_init_request;
408 Z_GDU *init_pdu = actual_init_request.get();
409
410 assert(init_pdu->which == Z_GDU_Z3950);
411 assert(init_pdu->u.z3950->which == Z_APDU_initRequest);
412
413 Z_InitRequest *req = init_pdu->u.z3950->u.initRequest;
414 ODR_MASK_ZERO(req->options);
415
416 ODR_MASK_SET(req->options, Z_Options_search);
417 ODR_MASK_SET(req->options, Z_Options_present);
418 ODR_MASK_SET(req->options, Z_Options_namedResultSets);
419 ODR_MASK_SET(req->options, Z_Options_scan);
420
421 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
422 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
423 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
424
426 *req->preferredMessageSize = m_preferredMessageSize;
428 *req->maximumRecordSize = m_maximumRecordSize;
429
430 init_package.request() = init_pdu;
431
432 {
433 boost::mutex::scoped_lock lock(m_mutex_backend_class);
434 m_no_init++;
435 }
436
437 init_package.move();
438
439 boost::mutex::scoped_lock lock(m_mutex_backend_class);
440
441 addinfo.clear();
442 code = 0;
443 m_named_result_sets = false;
444 Z_GDU *gdu = init_package.response().get();
445
446 if (gdu && gdu->which == Z_GDU_Z3950
447 && gdu->u.z3950->which == Z_APDU_initResponse)
448 {
449 Z_InitResponse *res = gdu->u.z3950->u.initResponse;
450
451 if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
452 {
453 m_named_result_sets = true;
454 }
455 // save init-response until we get one that succeeds
456 if (m_no_succeeded == 0)
457 m_init_response = gdu->u.z3950;
458 if (*gdu->u.z3950->u.initResponse->result
459 && !init_package.session().is_closed())
460 {
461 bp->m_in_use = true;
462 time(&bp->m_time_last_use);
463 bp->m_sequence_this = 0;
464 bp->m_result_set_sequence = 0;
465 m_backend_list.push_back(bp);
467 return bp;
468 }
469 else
470 {
471 Z_External *uif =
472 gdu->u.z3950->u.initResponse->userInformationField;
473 if (uif && uif->which == Z_External_userInfo1)
474 {
475 Z_OtherInformation *ui = uif->u.userInfo1;
476 if (ui && ui->num_elements >= 1)
477 {
478 Z_OtherInformationUnit *unit = ui->list[0];
479 if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
480 unit->information.externallyDefinedInfo &&
481 unit->information.externallyDefinedInfo->which ==
482 Z_External_diag1)
483 {
484 Z_DiagnosticFormat *diag =
485 unit->information.externallyDefinedInfo->u.diag1;
486 if (diag->num >= 1)
487 {
488 Z_DiagnosticFormat_s *ds = diag->elements[0];
489 if (ds->which ==
490 Z_DiagnosticFormat_s_defaultDiagRec)
491 {
492 Z_DefaultDiagFormat *e =
493 ds->u.defaultDiagRec;
494 code = *e->condition;
495 if (e->which == Z_DefaultDiagFormat_v2Addinfo
496 && e->u.v2Addinfo)
497 {
498 addinfo = e->u.v2Addinfo;
499 }
500 else if (
501 e->which == Z_DefaultDiagFormat_v3Addinfo
502 && e->u.v3Addinfo)
503 {
504 addinfo = e->u.v3Addinfo;
505 }
506 }
507 }
508 }
509 }
510 }
511 }
512 }
513 if (!init_package.session().is_closed())
514 {
515 init_package.copy_filter(frontend_package);
516 init_package.session().close();
517 init_package.move();
518 }
519 m_no_failed++;
520 m_cond_set_ready.notify_all();
521 return null;
522}
523
524
525yf::SessionShared::BackendClass::BackendClass(const yazpp_1::GDU &init_request,
526 int resultset_ttl,
527 int resultset_max,
528 int session_ttl,
529 Odr_int preferredMessageSize,
530 Odr_int maximumRecordSize)
531 : m_named_result_sets(false), m_init_request(init_request),
532 m_sequence_top(0), m_backend_set_ttl(resultset_ttl),
533 m_backend_expiry_ttl(session_ttl), m_backend_set_max(resultset_max),
534 m_preferredMessageSize(preferredMessageSize),
535 m_maximumRecordSize(maximumRecordSize),
537{}
538
541
542void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
543 FrontendPtr frontend)
544{
545 Z_InitRequest *req = gdu->u.z3950->u.initRequest;
546
547 frontend->m_is_virtual = true;
548 frontend->m_init_options = *req->options;
549 if (m_ignore_auth)
550 req->idAuthentication = 0;
551 InitKey k(req);
552 {
553 boost::mutex::scoped_lock lock(m_mutex_backend_map);
554 BackendClassMap::const_iterator it;
555 it = m_backend_map.find(k);
556 if (it == m_backend_map.end())
557 {
558 BackendClassPtr b(new BackendClass(gdu->u.z3950,
564 m_backend_map[k] = b;
565 frontend->m_backend_class = b;
566 }
567 else
568 {
569 frontend->m_backend_class = it->second;
570 }
571 }
572 BackendClassPtr bc = frontend->m_backend_class;
573 mp::odr odr;
574
575 // we only need to get init response from "first" target in
576 // backend class - the assumption being that init response is
577 // same for all
578 bool create_first_one = false;
579 {
580 boost::mutex::scoped_lock lock(bc->m_mutex_backend_class);
581 if (!bc->m_no_succeeded)
582 create_first_one = true;
583 else
584 {
585 // wait for first one to finish
586 while (!bc->m_no_failed && !bc->m_no_succeeded && bc->m_no_init)
587 {
588 bc->m_cond_set_ready.wait(lock);
589 }
590 }
591 }
592 if (create_first_one)
593 {
594
595 int code;
596 std::string addinfo;
597 BackendInstancePtr backend = bc->create_backend(package, code, addinfo);
598 if (backend)
599 bc->release_backend(backend);
600 }
601 yazpp_1::GDU init_response;
602 {
603 boost::mutex::scoped_lock lock(bc->m_mutex_backend_class);
604
605 init_response = bc->m_init_response;
606 }
607
608 if (init_response.get())
609 {
610 Z_GDU *response_gdu = init_response.get();
611 mp::util::transfer_referenceId(odr, gdu->u.z3950,
612 response_gdu->u.z3950);
613 Z_InitResponse *init_res = response_gdu->u.z3950->u.initResponse;
614 Z_Options *server_options = init_res->options;
615 Z_Options *client_options = &frontend->m_init_options;
616 int i;
617 for (i = 0; i < 30; i++)
618 if (!ODR_MASK_GET(client_options, i))
619 ODR_MASK_CLEAR(server_options, i);
620
622 *init_res->preferredMessageSize > *req->preferredMessageSize)
623 *init_res->preferredMessageSize = *req->preferredMessageSize;
624
625 if (!m_maximumRecordSize ||
626 *init_res->maximumRecordSize > *req->maximumRecordSize)
627 *init_res->maximumRecordSize = *req->maximumRecordSize;
628
629 package.response() = init_response;
630 if (!*response_gdu->u.z3950->u.initResponse->result)
631 package.session().close();
632 }
633 else
634 {
635 Z_APDU *apdu =
636 odr.create_initResponse(
637 gdu->u.z3950, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
638 "session_shared: target closed connection during init");
639 *apdu->u.initResponse->result = 0;
640 package.response() = apdu;
641 package.session().close();
642 }
643}
644
649
651 const std::string &result_set_id,
652 const Databases &databases,
653 const yazpp_1::Yaz_Z_Query &query,
654 Z_OtherInformation *additionalSearchInfo) :
655 m_result_set_id(result_set_id),
656 m_databases(databases), m_result_set_size(0), m_query(query)
657{
658 timestamp();
659 mem_additionalSearchInfo = nmem_create();
662 yaz_clone_z_OtherInformation(additionalSearchInfo,
664}
665
670
671static int get_diagnostic(Z_DefaultDiagFormat *r)
672{
673 return *r->condition;
674}
675
677 mp::Package &frontend_package,
678 mp::Package &search_package,
679 const Z_APDU *frontend_apdu,
680 const BackendInstancePtr bp,
681 Z_Records **z_records)
682{
683 mp::odr odr;
684 Z_APDU *apdu_req = zget_APDU(odr, Z_APDU_searchRequest);
685 Z_SearchRequest *req = apdu_req->u.searchRequest;
686
687 req->additionalSearchInfo = additionalSearchInfoRequest;
688 req->resultSetName = odr_strdup(odr, m_result_set_id.c_str());
689 req->query = m_query.get_Z_Query();
690
691 req->num_databaseNames = m_databases.size();
692 req->databaseNames = (char**)
693 odr_malloc(odr, req->num_databaseNames * sizeof(char *));
694 Databases::const_iterator it = m_databases.begin();
695 size_t i = 0;
696 for (; it != m_databases.end(); it++)
697 req->databaseNames[i++] = odr_strdup(odr, it->c_str());
698
699 if (frontend_apdu->which == Z_APDU_searchRequest)
700 req->preferredRecordSyntax =
701 frontend_apdu->u.searchRequest->preferredRecordSyntax;
702
703 search_package.request() = apdu_req;
704
705 search_package.move();
706
707 Z_GDU *gdu = search_package.response().get();
708 if (!search_package.session().is_closed()
709 && gdu && gdu->which == Z_GDU_Z3950
710 && gdu->u.z3950->which == Z_APDU_searchResponse)
711 {
712 Z_SearchResponse *b_resp = gdu->u.z3950->u.searchResponse;
713 *z_records = b_resp->records;
714 m_result_set_size = *b_resp->resultCount;
715
716 additionalSearchInfoResponse = yaz_clone_z_OtherInformation(
717 b_resp->additionalSearchInfo, mem_additionalSearchInfo);
718 return true;
719 }
720 Z_APDU *f_apdu = 0;
721 const char *addinfo = "session_shared: "
722 "target closed connection during search";
723 if (frontend_apdu->which == Z_APDU_searchRequest)
724 f_apdu = odr.create_searchResponse(
725 frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
726 else if (frontend_apdu->which == Z_APDU_presentRequest)
727 f_apdu = odr.create_presentResponse(
728 frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
729 else
730 f_apdu = odr.create_close(
731 frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
732 frontend_package.response() = f_apdu;
733 return false;
734}
735
737 BackendInstancePtr &found_backend,
738 std::string &result_set_id,
739 const Databases &databases,
740 bool out_of_sessions)
741{
743 BackendInstanceList::const_iterator it = bc->m_backend_list.begin();
744 time_t now;
745 time(&now);
746
747 size_t max_sets = bc->m_named_result_sets ? bc->m_backend_set_max : 1;
748 for (; it != bc->m_backend_list.end(); it++)
749 {
750 if (!(*it)->m_in_use)
751 {
752 BackendSetList::iterator set_it = (*it)->m_sets.begin();
753 for (; set_it != (*it)->m_sets.end(); set_it++)
754 {
755 bool same_databases = mp::util::match((*set_it)->m_databases,
756 databases);
757 if ((max_sets > 1 || same_databases)
758 &&
759 (out_of_sessions ||
760 now < (*set_it)->m_time_last_use ||
761 now - (*set_it)->m_time_last_use >= bc->m_backend_set_ttl))
762 {
763 found_backend = *it;
764 result_set_id = (*set_it)->m_result_set_id;
765 found_backend->m_sets.erase(set_it);
766 return;
767 }
768 }
769 }
770 }
771 for (it = bc->m_backend_list.begin(); it != bc->m_backend_list.end(); it++)
772 {
773 if (!(*it)->m_in_use && (*it)->m_sets.size() < max_sets)
774 {
775 found_backend = *it;
776 if (bc->m_named_result_sets)
777 {
778 result_set_id = boost::io::str(
779 boost::format("%1%") %
780 found_backend->m_result_set_sequence);
781 found_backend->m_result_set_sequence++;
782 }
783 else
784 result_set_id = "default";
785 return;
786 }
787 }
788}
789
790void yf::SessionShared::Frontend::get_set(mp::Package &package,
791 const Z_APDU *apdu_req,
792 const Databases &databases,
793 yazpp_1::Yaz_Z_Query &query,
794 BackendInstancePtr &found_backend,
795 BackendSetPtr &found_set)
796{
797 bool session_restarted = false;
798 Z_OtherInformation *additionalSearchInfo = 0;
799
800 if (apdu_req->which == Z_APDU_searchRequest)
801 additionalSearchInfo = apdu_req->u.searchRequest->additionalSearchInfo;
802
803restart:
804 std::string result_set_id;
805 bool out_of_sessions = false;
807 {
808 boost::mutex::scoped_lock lock(bc->m_mutex_backend_class);
809
810 if ((int) bc->m_backend_list.size() >= m_p->m_session_max)
811 out_of_sessions = true;
812
813 if (m_p->m_optimize_search)
814 {
815 // look at each backend and see if we have a similar search
816 BackendInstanceList::const_iterator it = bc->m_backend_list.begin();
817 while (it != bc->m_backend_list.end())
818 {
819 bool restart = false;
820 BackendSetList::const_iterator set_it = (*it)->m_sets.begin();
821 for (; set_it != (*it)->m_sets.end(); set_it++)
822 {
823 // for real present request we don't care
824 // if additionalSearchInfo matches: same records
825 if (mp::util::match((*set_it)->m_databases, databases)
826 && query.match(&(*set_it)->m_query)
827 && (apdu_req->which != Z_APDU_searchRequest ||
828 yaz_compare_z_OtherInformation(
829 additionalSearchInfo,
830 (*set_it)->additionalSearchInfoRequest)))
831 {
832 if ((*it)->m_in_use)
833 {
834 bc->m_cond_set_ready.wait(lock);
835 restart = true;
836 break;
837 }
838 else
839 {
840 found_set = *set_it;
841 found_backend = *it;
842 bc->use_backend(found_backend);
843 // found matching set. No need to search again
844 return;
845 }
846 }
847 }
848 if (restart)
849 it = bc->m_backend_list.begin();
850 else
851 it++;
852 }
853 }
854 override_set(found_backend, result_set_id, databases, out_of_sessions);
855 if (found_backend)
856 bc->use_backend(found_backend);
857 }
858 if (!found_backend)
859 {
860 int code;
861 std::string addinfo;
862 // create a new backend set (and new set) if we're not out of sessions
863 if (!out_of_sessions)
864 found_backend = bc->create_backend(package, code, addinfo);
865 if (!found_backend)
866 {
867 Z_APDU *f_apdu = 0;
868 mp::odr odr;
869
870 if (out_of_sessions)
871 {
872 code = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
873 addinfo = "session_shared: all sessions in use";
874 }
875 else
876 {
877 if (code == 0)
878 code = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
879 if (addinfo.length() == 0)
880 addinfo = "session_shared: could not create backend";
881 }
882 if (apdu_req->which == Z_APDU_searchRequest)
883 {
884 f_apdu = odr.create_searchResponse(
885 apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo.c_str());
886 }
887 else if (apdu_req->which == Z_APDU_presentRequest)
888 {
889 f_apdu = odr.create_presentResponse(
890 apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo.c_str());
891 }
892 else
893 {
894 f_apdu = odr.create_close(
895 apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo.c_str());
896 }
897 package.response() = f_apdu;
898 return;
899 }
900 if (bc->m_named_result_sets)
901 {
902 result_set_id = boost::io::str(
903 boost::format("%1%") % found_backend->m_result_set_sequence);
904 found_backend->m_result_set_sequence++;
905 }
906 else
907 result_set_id = "default";
908 }
909 found_backend->timestamp();
910
911 // we must search ...
912 BackendSetPtr new_set(new BackendSet(result_set_id,
913 databases, query,
914 additionalSearchInfo));
915
916 found_set = new_set;
917 found_set->timestamp();
918
919 Z_Records *z_records = 0;
920
921 Package search_package(found_backend->m_session, package.origin());
922 search_package.copy_filter(package);
923
924 if (!new_set->search(package, search_package,
925 apdu_req, found_backend, &z_records))
926 {
927 bc->remove_backend(found_backend);
928 found_set.reset();
929 return; // search error
930 }
931
932 if (z_records)
933 {
934 int condition = 0;
935 if (z_records->which == Z_Records_NSD)
936 {
937 condition =
938 get_diagnostic(z_records->u.nonSurrogateDiagnostic);
939 }
940 else if (z_records->which == Z_Records_multipleNSD)
941 {
942 if (z_records->u.multipleNonSurDiagnostics->num_diagRecs >= 1
943 &&
944
945 z_records->u.multipleNonSurDiagnostics->diagRecs[0]->which ==
946 Z_DiagRec_defaultFormat)
947 {
948 condition = get_diagnostic(
949 z_records->u.multipleNonSurDiagnostics->diagRecs[0]->u.defaultFormat);
950
951 }
952 }
953 if (m_p->m_restart && !session_restarted &&
954 condition == YAZ_BIB1_TEMPORARY_SYSTEM_ERROR)
955 {
956 package.log("session_shared", YLOG_LOG, "restart");
957 bc->remove_backend(found_backend);
958 session_restarted = true;
959 found_backend.reset();
960 goto restart;
961
962 }
963
964 if (condition)
965 {
966 mp::odr odr;
967 if (apdu_req->which == Z_APDU_searchRequest)
968 {
969 Z_APDU *f_apdu = odr.create_searchResponse(apdu_req,
970 0, 0);
971 Z_SearchResponse *f_resp = f_apdu->u.searchResponse;
972 *f_resp->searchStatus = Z_SearchResponse_none;
973 f_resp->records = z_records;
974 package.response() = f_apdu;
975 }
976 if (apdu_req->which == Z_APDU_presentRequest)
977 {
978 Z_APDU *f_apdu = odr.create_presentResponse(apdu_req,
979 0, 0);
980 Z_PresentResponse *f_resp = f_apdu->u.presentResponse;
981 f_resp->records = z_records;
982 package.response() = f_apdu;
983 }
984 bc->release_backend(found_backend);
985 found_set.reset();
986 return; // search error
987 }
988 }
989 if (m_p->m_restart && !session_restarted && new_set->m_result_set_size < 0)
990 {
991 package.log("session_shared", YLOG_LOG, "restart");
992 bc->remove_backend(found_backend);
993 session_restarted = true;
994 found_backend.reset();
995 goto restart;
996 }
997 found_backend->m_sets.push_back(found_set);
998}
999
1001 const Databases &databases,
1002 Z_RPNStructure *s,
1003 std::string &rset)
1004{
1005 int ret = 0;
1006 switch (s->which)
1007 {
1008 case Z_RPNStructure_simple:
1009 if (s->u.simple->which == Z_Operand_resultSetId)
1010 {
1011 const char *id = s->u.simple->u.resultSetId;
1012 rset = id;
1013
1014 FrontendSets::iterator fset_it = m_frontend_sets.find(id);
1015 if (fset_it == m_frontend_sets.end())
1016 {
1017 ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
1018 }
1019 else if (!mp::util::match(fset_it->second->get_databases(),
1020 databases))
1021 {
1022 ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
1023 }
1024 else
1025 {
1026 yazpp_1::Yaz_Z_Query query = fset_it->second->get_query();
1027 Z_Query *q = yaz_copy_Z_Query(query.get_Z_Query(), o);
1028 if (q->which == Z_Query_type_1 || q->which == Z_Query_type_101)
1029 {
1030 s->which = q->u.type_1->RPNStructure->which;
1031 s->u.simple = q->u.type_1->RPNStructure->u.simple;
1032 }
1033 else
1034 {
1035 ret = YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST;
1036 }
1037 }
1038 }
1039 break;
1040 case Z_RPNStructure_complex:
1041 ret = result_set_ref(o, databases, s->u.complex->s1, rset);
1042 if (!ret)
1043 ret = result_set_ref(o, databases, s->u.complex->s2, rset);
1044 break;
1045 }
1046 return ret;
1047}
1048
1049void yf::SessionShared::Frontend::search(mp::Package &package,
1050 Z_APDU *apdu_req)
1051{
1052 Z_SearchRequest *req = apdu_req->u.searchRequest;
1053 FrontendSets::iterator fset_it =
1054 m_frontend_sets.find(req->resultSetName);
1055 if (fset_it != m_frontend_sets.end())
1056 {
1057 // result set already exist
1058 // if replace indicator is off: we return diagnostic if
1059 // result set already exist.
1060 if (*req->replaceIndicator == 0)
1061 {
1062 mp::odr odr;
1063 Z_APDU *apdu =
1064 odr.create_searchResponse(
1065 apdu_req,
1066 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
1067 0);
1068 package.response() = apdu;
1069 return;
1070 }
1071 m_frontend_sets.erase(fset_it);
1072 }
1073
1074 Databases databases;
1075 int i;
1076 for (i = 0; i < req->num_databaseNames; i++)
1077 databases.push_back(req->databaseNames[i]);
1078
1079
1080 yazpp_1::Yaz_Z_Query query;
1081 query.set_Z_Query(req->query);
1082
1083 Z_Query *q = query.get_Z_Query();
1084 if (q->which == Z_Query_type_1 || q->which == Z_Query_type_101)
1085 {
1086 mp::odr odr;
1087 std::string rset;
1088 int diag = result_set_ref(odr, databases, q->u.type_1->RPNStructure,
1089 rset);
1090 if (diag)
1091 {
1092 Z_APDU *apdu =
1093 odr.create_searchResponse(
1094 apdu_req,
1095 diag,
1096 rset.c_str());
1097 package.response() = apdu;
1098 return;
1099 }
1100 query.set_Z_Query(q);
1101 }
1102
1103 BackendSetPtr found_set; // null
1104 BackendInstancePtr found_backend; // null
1105
1106 get_set(package, apdu_req, databases, query, found_backend, found_set);
1107 if (!found_set)
1108 return;
1109
1110 mp::odr odr;
1111 Z_APDU *f_apdu = odr.create_searchResponse(apdu_req, 0, 0);
1112 Z_SearchResponse *f_resp = f_apdu->u.searchResponse;
1113 *f_resp->resultCount = found_set->m_result_set_size;
1114 f_resp->additionalSearchInfo = found_set->additionalSearchInfoResponse;
1115 package.response() = f_apdu;
1116
1117 FrontendSetPtr fset(new FrontendSet(databases, query));
1118 m_frontend_sets[req->resultSetName] = fset;
1119
1120 m_backend_class->release_backend(found_backend);
1121}
1122
1124 Z_APDU *apdu_req)
1125{
1126 mp::odr odr;
1127 Z_PresentRequest *req = apdu_req->u.presentRequest;
1128
1129 FrontendSets::iterator fset_it =
1130 m_frontend_sets.find(req->resultSetId);
1131
1132 if (fset_it == m_frontend_sets.end())
1133 {
1134 Z_APDU *apdu =
1135 odr.create_presentResponse(
1136 apdu_req,
1137 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
1138 req->resultSetId);
1139 package.response() = apdu;
1140 return;
1141 }
1142 FrontendSetPtr fset = fset_it->second;
1143
1144 Databases databases = fset->get_databases();
1145 yazpp_1::Yaz_Z_Query query = fset->get_query();
1146
1148 BackendSetPtr found_set; // null
1149 BackendInstancePtr found_backend;
1150
1151 get_set(package, apdu_req, databases, query, found_backend, found_set);
1152 if (!found_set)
1153 return;
1154
1155 Z_NamePlusRecordList *npr_res = 0;
1156 // record_cache.lookup types are int's. Avoid non-fitting values
1157 if (*req->resultSetStartPoint > 0
1158 && *req->resultSetStartPoint < INT_MAX
1159 && *req->numberOfRecordsRequested > 0
1160 && *req->numberOfRecordsRequested < INT_MAX
1161 && found_set->m_record_cache.lookup(odr, &npr_res,
1162 *req->resultSetStartPoint,
1163 *req->numberOfRecordsRequested,
1164 req->preferredRecordSyntax,
1165 req->recordComposition))
1166 {
1167 Z_APDU *f_apdu_res = odr.create_presentResponse(apdu_req, 0, 0);
1168 Z_PresentResponse *f_resp = f_apdu_res->u.presentResponse;
1169
1170 yaz_log(YLOG_LOG, "Found " ODR_INT_PRINTF "+" ODR_INT_PRINTF
1171 " records in cache %p",
1172 *req->resultSetStartPoint,
1173 *req->numberOfRecordsRequested,
1174 &found_set->m_record_cache);
1175
1176 *f_resp->numberOfRecordsReturned = *req->numberOfRecordsRequested;
1177 *f_resp->nextResultSetPosition =
1178 *req->resultSetStartPoint + *req->numberOfRecordsRequested;
1179 // f_resp->presentStatus assumed OK.
1180 f_resp->records = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
1181 f_resp->records->which = Z_Records_DBOSD;
1182 f_resp->records->u.databaseOrSurDiagnostics = npr_res;
1183 package.response() = f_apdu_res;
1184 bc->release_backend(found_backend);
1185 return;
1186 }
1187
1188 found_backend->timestamp();
1189
1190 Z_APDU *p_apdu = zget_APDU(odr, Z_APDU_presentRequest);
1191 Z_PresentRequest *p_req = p_apdu->u.presentRequest;
1192 p_req->preferredRecordSyntax = req->preferredRecordSyntax;
1193 p_req->resultSetId = odr_strdup(odr, found_set->m_result_set_id.c_str());
1194 *p_req->resultSetStartPoint = *req->resultSetStartPoint;
1195 *p_req->numberOfRecordsRequested = *req->numberOfRecordsRequested;
1196 p_req->preferredRecordSyntax = req->preferredRecordSyntax;
1197 p_req->recordComposition = req->recordComposition;
1198
1199 Package present_package(found_backend->m_session, package.origin());
1200 present_package.copy_filter(package);
1201
1202 present_package.request() = p_apdu;
1203
1204 present_package.move();
1205
1206 Z_GDU *gdu = present_package.response().get();
1207 if (!present_package.session().is_closed()
1208 && gdu && gdu->which == Z_GDU_Z3950
1209 && gdu->u.z3950->which == Z_APDU_presentResponse)
1210 {
1211 Z_PresentResponse *b_resp = gdu->u.z3950->u.presentResponse;
1212 Z_APDU *f_apdu_res = odr.create_presentResponse(apdu_req, 0, 0);
1213 Z_PresentResponse *f_resp = f_apdu_res->u.presentResponse;
1214
1215 f_resp->numberOfRecordsReturned = b_resp->numberOfRecordsReturned;
1216 f_resp->nextResultSetPosition = b_resp->nextResultSetPosition;
1217 f_resp->presentStatus= b_resp->presentStatus;
1218 f_resp->records = b_resp->records;
1219 f_resp->otherInfo = b_resp->otherInfo;
1220 package.response() = f_apdu_res;
1221
1222 if (b_resp->records && b_resp->records->which == Z_Records_DBOSD)
1223 {
1224 Z_NamePlusRecordList *npr =
1225 b_resp->records->u.databaseOrSurDiagnostics;
1226 // record_cache.add types are int's. Avoid non-fitting values
1227 if (*req->resultSetStartPoint > 0
1228 && npr->num_records + *req->resultSetStartPoint < INT_MAX)
1229 {
1230#if 0
1231 yaz_log(YLOG_LOG, "Adding " ODR_INT_PRINTF "+" ODR_INT_PRINTF
1232 " records to cache %p",
1233 *req->resultSetStartPoint,
1234 *f_resp->numberOfRecordsReturned,
1235 &found_set->m_record_cache);
1236#endif
1237 found_set->m_record_cache.add(
1238 odr, npr, *req->resultSetStartPoint,
1239 p_req->recordComposition);
1240 }
1241 }
1242 bc->release_backend(found_backend);
1243 }
1244 else
1245 {
1246 bc->remove_backend(found_backend);
1247 Z_APDU *f_apdu_res =
1248 odr.create_presentResponse(
1249 apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
1250 "session_shared: target closed connection during present");
1251 package.response() = f_apdu_res;
1252 }
1253}
1254
1255void yf::SessionShared::Frontend::scan(mp::Package &frontend_package,
1256 Z_APDU *apdu_req)
1257{
1259 int code;
1260 std::string addinfo;
1261 BackendInstancePtr backend = bc->get_backend(frontend_package,
1262 code, addinfo);
1263 if (!backend)
1264 {
1265 mp::odr odr;
1266 if (code == 0)
1267 code = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
1268 if (addinfo.length() == 0)
1269 addinfo = "session_shared: could not create backend";
1270 Z_APDU *apdu = odr.create_scanResponse(
1271 apdu_req, code, addinfo.c_str());
1272 frontend_package.response() = apdu;
1273 }
1274 else
1275 {
1276 Package scan_package(backend->m_session, frontend_package.origin());
1277 backend->timestamp();
1278 scan_package.copy_filter(frontend_package);
1279 scan_package.request() = apdu_req;
1280 scan_package.move();
1281 frontend_package.response() = scan_package.response();
1282 if (scan_package.session().is_closed())
1283 {
1284 frontend_package.session().close();
1285 bc->remove_backend(backend);
1286 }
1287 else
1288 bc->release_backend(backend);
1289 }
1290}
1291
1295
1297{
1298 m_p->expire();
1299}
1300
1302{
1303 time_t now;
1304 time(&now);
1305 boost::mutex::scoped_lock lock(m_mutex_backend_class);
1306 BackendInstanceList::iterator bit = m_backend_list.begin();
1307 while (bit != m_backend_list.end())
1308 {
1309 time_t last_use = (*bit)->m_time_last_use;
1310
1311 if ((*bit)->m_in_use)
1312 {
1313 yaz_log(YLOG_LOG, "session_shared id=%ld in_use",
1314 (*bit)->m_session.id());
1315 bit++;
1316 }
1317 else if (now < last_use || now - last_use > m_backend_expiry_ttl)
1318 {
1319 yaz_log(YLOG_LOG, "session_shared id=%ld erase",
1320 (*bit)->m_session.id());
1321 bit = m_backend_list.erase(bit);
1322 }
1323 else
1324 {
1325 yaz_log(YLOG_LOG, "session_shared id=%ld skip now-last_use=%ld",
1326 (*bit)->m_session.id(), (long) (now - last_use));
1327 bit++;
1328 }
1329 }
1330 if (m_backend_list.empty())
1331 return true;
1332 return false;
1333}
1334
1336{
1337 boost::mutex::scoped_lock lock(m_mutex_backend_map);
1338 BackendClassMap::iterator b_it = m_backend_map.begin();
1339 while (b_it != m_backend_map.end())
1340 {
1341 if (b_it->second->expire_instances())
1342 {
1343 m_backend_map.erase(b_it);
1344 b_it = m_backend_map.begin();
1345 }
1346 else
1347 b_it++;
1348 }
1349}
1350
1352{
1353 while (true)
1354 {
1355 boost::xtime xt;
1356 boost::xtime_get(&xt,
1357#if BOOST_VERSION >= 105000
1358 boost::TIME_UTC_
1359#else
1360 boost::TIME_UTC
1361#endif
1362 );
1363 xt.sec += m_session_ttl;
1364 {
1365 boost::mutex::scoped_lock lock(m_mutex);
1366 m_cond_expire_ready.timed_wait(lock, xt);
1367 if (close_down)
1368 break;
1369 }
1371 }
1372}
1373
1375{
1376 m_resultset_ttl = 30;
1377 m_resultset_max = 10;
1378 m_session_ttl = 90;
1379 m_optimize_search = true;
1380 m_ignore_auth = false;
1381 m_restart = false;
1382 m_session_max = 100;
1385 close_down = false;
1386}
1387
1389{
1390 {
1391 boost::mutex::scoped_lock lock(m_mutex);
1392 close_down = true;
1393 m_cond_expire_ready.notify_all();
1394 }
1395 m_thrds.join_all();
1396}
1397
1399{
1401 m_thrds.add_thread(new boost::thread(w));
1402}
1403
1407
1410
1412{
1413 m_p->start();
1414}
1415
1419
1423
1425{
1426 boost::mutex::scoped_lock lock(m_mutex);
1427
1428 std::map<mp::Session,yf::SessionShared::FrontendPtr>::iterator it;
1429
1430 while(true)
1431 {
1432 it = m_clients.find(package.session());
1433 if (it == m_clients.end())
1434 break;
1435
1436 if (!it->second->m_in_use)
1437 {
1438 it->second->m_in_use = true;
1439 return it->second;
1440 }
1441 m_cond_session_ready.wait(lock);
1442 }
1443 FrontendPtr f(new Frontend(this));
1444 m_clients[package.session()] = f;
1445 f->m_in_use = true;
1446 return f;
1447}
1448
1450{
1451 boost::mutex::scoped_lock lock(m_mutex);
1452 std::map<mp::Session,yf::SessionShared::FrontendPtr>::iterator it;
1453
1454 it = m_clients.find(package.session());
1455 if (it != m_clients.end())
1456 {
1457 if (package.session().is_closed())
1458 {
1459 m_clients.erase(it);
1460 }
1461 else
1462 {
1463 it->second->m_in_use = false;
1464 }
1465 m_cond_session_ready.notify_all();
1466 }
1467}
1468
1469
1470void yf::SessionShared::process(mp::Package &package) const
1471{
1472 FrontendPtr f = m_p->get_frontend(package);
1473
1474 Z_GDU *gdu = package.request().get();
1475
1476 if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
1477 Z_APDU_initRequest && !f->m_is_virtual)
1478 {
1479 m_p->init(package, gdu, f);
1480 }
1481 else if (!f->m_is_virtual)
1482 package.move();
1483 else if (gdu && gdu->which == Z_GDU_Z3950)
1484 {
1485 Z_APDU *apdu = gdu->u.z3950;
1486 if (apdu->which == Z_APDU_initRequest)
1487 {
1488 mp::odr odr;
1489
1490 package.response() = odr.create_close(
1491 apdu,
1492 Z_Close_protocolError,
1493 "double init");
1494
1495 package.session().close();
1496 }
1497 else if (apdu->which == Z_APDU_close)
1498 {
1499 mp::odr odr;
1500
1501 package.response() = odr.create_close(
1502 apdu,
1503 Z_Close_peerAbort, "received close from client");
1504 package.session().close();
1505 }
1506 else if (apdu->which == Z_APDU_searchRequest)
1507 {
1508 f->search(package, apdu);
1509 }
1510 else if (apdu->which == Z_APDU_presentRequest)
1511 {
1512 f->present(package, apdu);
1513 }
1514 else if (apdu->which == Z_APDU_scanRequest)
1515 {
1516 f->scan(package, apdu);
1517 }
1518 else
1519 {
1520 mp::odr odr;
1521
1522 package.response() = odr.create_close(
1523 apdu, Z_Close_protocolError,
1524 "unsupported APDU in filter_session_shared");
1525
1526 package.session().close();
1527 }
1528 }
1529 m_p->release_frontend(package);
1530}
1531
1532void yf::SessionShared::configure(const xmlNode *ptr, bool test_only,
1533 const char *path)
1534{
1535 for (ptr = ptr->children; ptr; ptr = ptr->next)
1536 {
1537 if (ptr->type != XML_ELEMENT_NODE)
1538 continue;
1539 if (!strcmp((const char *) ptr->name, "resultset"))
1540 {
1541 const struct _xmlAttr *attr;
1542 for (attr = ptr->properties; attr; attr = attr->next)
1543 {
1544 if (!strcmp((const char *) attr->name, "ttl"))
1545 m_p->m_resultset_ttl =
1546 mp::xml::get_int(attr->children, 30);
1547 else if (!strcmp((const char *) attr->name, "max"))
1548 {
1549 m_p->m_resultset_max =
1550 mp::xml::get_int(attr->children, 10);
1551 }
1552 else if (!strcmp((const char *) attr->name, "optimizesearch"))
1553 {
1554 m_p->m_optimize_search =
1555 mp::xml::get_bool(attr->children, true);
1556 }
1557 else if (!strcmp((const char *) attr->name, "restart"))
1558 {
1559 m_p->m_restart = mp::xml::get_bool(attr->children, true);
1560 }
1561 else
1562 throw mp::filter::FilterException(
1563 "Bad attribute " + std::string((const char *)
1564 attr->name));
1565 }
1566 }
1567 else if (!strcmp((const char *) ptr->name, "session"))
1568 {
1569 const struct _xmlAttr *attr;
1570 for (attr = ptr->properties; attr; attr = attr->next)
1571 {
1572 if (!strcmp((const char *) attr->name, "ttl"))
1573 m_p->m_session_ttl =
1574 mp::xml::get_int(attr->children, 90);
1575 else if (!strcmp((const char *) attr->name, "max"))
1576 m_p->m_session_max =
1577 mp::xml::get_int(attr->children, 100);
1578 else
1579 throw mp::filter::FilterException(
1580 "Bad attribute " + std::string((const char *)
1581 attr->name));
1582 }
1583 }
1584 else if (!strcmp((const char *) ptr->name, "init"))
1585 {
1586 const struct _xmlAttr *attr;
1587 for (attr = ptr->properties; attr; attr = attr->next)
1588 {
1589 if (!strcmp((const char *) attr->name, "maximum-record-size"))
1590 m_p->m_maximumRecordSize =
1591 mp::xml::get_int(attr->children, 0);
1592 else if (!strcmp((const char *) attr->name,
1593 "preferred-message-size"))
1594 m_p->m_preferredMessageSize =
1595 mp::xml::get_int(attr->children, 0);
1596 else if (!strcmp((const char *) attr->name,
1597 "ignore-auth"))
1598 m_p->m_ignore_auth =
1599 mp::xml::get_bool(attr->children, false);
1600 else
1601 throw mp::filter::FilterException(
1602 "Bad attribute " + std::string((const char *)
1603 attr->name));
1604 }
1605 }
1606 else
1607 {
1608 throw mp::filter::FilterException("Bad element "
1609 + std::string((const char *)
1610 ptr->name));
1611 }
1612 }
1613}
1614
1615static mp::filter::Base* filter_creator()
1616{
1617 return new mp::filter::SessionShared;
1618}
1619
1620extern "C" {
1621 struct metaproxy_1_filter_struct metaproxy_1_filter_session_shared = {
1622 0,
1623 "session_shared",
1625 };
1626}
1627
1628/*
1629 * Local variables:
1630 * c-basic-offset: 4
1631 * c-file-style: "Stroustrup"
1632 * indent-tabs-mode: nil
1633 * End:
1634 * vim: shiftwidth=4 tabstop=8 expandtab
1635 */
1636
BackendInstancePtr create_backend(const Package &package, int &code, std::string &addinfo)
BackendClass(const yazpp_1::GDU &init_request, int resultset_ttl, int resultset_max, int session_ttl, Odr_int preferredRecordSize, Odr_int maximumRecordSize)
BackendInstancePtr get_backend(const Package &package, int &code, std::string &addinfo)
BackendSet(const std::string &result_set_id, const Databases &databases, const yazpp_1::Yaz_Z_Query &query, Z_OtherInformation *additionalSearchInfoRequest)
bool search(Package &frontend_package, Package &search_package, const Z_APDU *apdu_req, const BackendInstancePtr bp, Z_Records **z_records)
bool operator<(const SessionShared::InitKey &k) const
void init(Package &package, const Z_GDU *gdu, FrontendPtr frontend)
std::map< mp::Session, FrontendPtr > m_clients
std::list< BackendSetPtr > BackendSetList
boost::shared_ptr< BackendInstance > BackendInstancePtr
boost::shared_ptr< BackendSet > BackendSetPtr
boost::shared_ptr< BackendClass > BackendClassPtr
std::list< BackendInstancePtr > BackendInstanceList
void process(metaproxy_1::Package &package) const
void configure(const xmlNode *ptr, bool test_only, const char *path)
std::map< InitKey, BackendClassPtr > BackendClassMap
boost::shared_ptr< FrontendSet > FrontendSetPtr
boost::shared_ptr< Frontend > FrontendPtr
std::map< std::string, FrontendSetPtr > FrontendSets
static mp::filter::Base * filter_creator()
static int get_diagnostic(Z_DefaultDiagFormat *r)
struct metaproxy_1_filter_struct metaproxy_1_filter_session_shared
int result_set_ref(ODR o, const Databases &databases, Z_RPNStructure *s, std::string &rset)
void override_set(BackendInstancePtr &found_backend, std::string &result_set_id, const Databases &databases, bool out_of_sessions)
void get_set(mp::Package &package, const Z_APDU *apdu_req, const Databases &databases, yazpp_1::Yaz_Z_Query &query, BackendInstancePtr &found_backend, BackendSetPtr &found_set)