http_client: better diagnostics MP-455
[metaproxy-moved-to-github.git] / src / filter_session_shared.cpp
index b2e00d7..038b467 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2012 Index Data
+   Copyright (C) 2005-2013 Index Data
 
 Metaproxy is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -125,11 +125,15 @@ namespace metaproxy_1 {
             time_t m_backend_set_ttl;
             time_t m_backend_expiry_ttl;
             size_t m_backend_set_max;
+            Odr_int m_preferredMessageSize;
+            Odr_int m_maximumRecordSize;
         public:
             BackendClass(const yazpp_1::GDU &init_request,
                          int resultset_ttl,
                          int resultset_max,
-                         int session_ttl);
+                         int session_ttl,
+                         Odr_int preferredRecordSize,
+                         Odr_int maximumRecordSize);
             ~BackendClass();
         };
         // frontend result set
@@ -197,6 +201,8 @@ namespace metaproxy_1 {
             bool m_optimize_search;
             bool m_restart;
             int m_session_max;
+            Odr_int m_preferredMessageSize;
+            Odr_int m_maximumRecordSize;
         };
     }
 }
@@ -382,6 +388,11 @@ yf::SessionShared::BackendInstancePtr yf::SessionShared::BackendClass::create_ba
     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
 
+    if (m_preferredMessageSize)
+        *req->preferredMessageSize = m_preferredMessageSize;
+    if (m_maximumRecordSize)
+        *req->maximumRecordSize = m_maximumRecordSize;
+
     init_package.request() = init_pdu;
 
     init_package.move();
@@ -390,48 +401,54 @@ yf::SessionShared::BackendInstancePtr yf::SessionShared::BackendClass::create_ba
 
     m_named_result_sets = false;
     Z_GDU *gdu = init_package.response().get();
-    if (init_package.session().is_closed())
-    {
-        /* already closed. We don't know why */
-        return null;
-    }
-    else if (gdu && gdu->which == Z_GDU_Z3950
-             && gdu->u.z3950->which == Z_APDU_initResponse
-             && *gdu->u.z3950->u.initResponse->result)
+
+    if (gdu && gdu->which == Z_GDU_Z3950
+        && gdu->u.z3950->which == Z_APDU_initResponse)
     {
-        /* successful init response */
         Z_InitResponse *res = gdu->u.z3950->u.initResponse;
         m_init_response = gdu->u.z3950;
         if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
         {
             m_named_result_sets = true;
         }
+        if (*gdu->u.z3950->u.initResponse->result
+            && !init_package.session().is_closed())
+        {
+            bp->m_in_use = true;
+            time(&bp->m_time_last_use);
+            bp->m_sequence_this = 0;
+            bp->m_result_set_sequence = 0;
+            m_backend_list.push_back(bp);
+            return bp;
+        }
     }
     else
     {
-        /* not init or init rejected */
+        yazpp_1::GDU empty_gdu;
+        m_init_response = empty_gdu;
+    }
+
+    if (!init_package.session().is_closed())
+    {
         init_package.copy_filter(frontend_package);
         init_package.session().close();
         init_package.move();
-        return null;
     }
-    bp->m_in_use = true;
-    time(&bp->m_time_last_use);
-    bp->m_sequence_this = 0;
-    bp->m_result_set_sequence = 0;
-    m_backend_list.push_back(bp);
-
-    return bp;
+    return null;
 }
 
 
 yf::SessionShared::BackendClass::BackendClass(const yazpp_1::GDU &init_request,
                                               int resultset_ttl,
                                               int resultset_max,
-                                              int session_ttl)
+                                              int session_ttl,
+                                              Odr_int preferredMessageSize,
+                                              Odr_int maximumRecordSize)
     : m_named_result_sets(false), m_init_request(init_request),
       m_sequence_top(0), m_backend_set_ttl(resultset_ttl),
-      m_backend_expiry_ttl(session_ttl), m_backend_set_max(resultset_max)
+      m_backend_expiry_ttl(session_ttl), m_backend_set_max(resultset_max),
+      m_preferredMessageSize(preferredMessageSize),
+      m_maximumRecordSize(maximumRecordSize)
 {}
 
 yf::SessionShared::BackendClass::~BackendClass()
@@ -454,7 +471,9 @@ void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
             BackendClassPtr b(new BackendClass(gdu->u.z3950,
                                                m_resultset_ttl,
                                                m_resultset_max,
-                                               m_session_ttl));
+                                               m_session_ttl,
+                                               m_preferredMessageSize,
+                                               m_maximumRecordSize));
             m_backend_map[k] = b;
             frontend->m_backend_class = b;
         }
@@ -464,45 +483,60 @@ void yf::SessionShared::Rep::init(mp::Package &package, const Z_GDU *gdu,
         }
     }
     BackendClassPtr bc = frontend->m_backend_class;
-    BackendInstancePtr backend;
     mp::odr odr;
 
     // we only need to get init response from "first" target in
     // backend class - the assumption being that init response is
     // same for all
-    if (bc->m_init_response.get() == 0)
+    if (bc->m_backend_list.size() == 0)
     {
-        backend = bc->get_backend(package);
+        BackendInstancePtr backend = bc->create_backend(package);
+        if (backend)
+            bc->release_backend(backend);
     }
+
+    yazpp_1::GDU init_response;
     {
         boost::mutex::scoped_lock lock(bc->m_mutex_backend_class);
-        if (bc->m_init_response.get() == 0)
-        {
-            Z_APDU *apdu = odr.create_initResponse(gdu->u.z3950, 0, 0);
-            *apdu->u.initResponse->result = 0;
-            package.response() = apdu;
+
+        init_response = bc->m_init_response;
+    }
+
+    if (init_response.get())
+    {
+        Z_GDU *response_gdu = init_response.get();
+        mp::util::transfer_referenceId(odr, gdu->u.z3950,
+                                       response_gdu->u.z3950);
+        Z_InitResponse *init_res = response_gdu->u.z3950->u.initResponse;
+        Z_Options *server_options = init_res->options;
+        Z_Options *client_options = &frontend->m_init_options;
+        int i;
+        for (i = 0; i < 30; i++)
+            if (!ODR_MASK_GET(client_options, i))
+                ODR_MASK_CLEAR(server_options, i);
+
+        if (!m_preferredMessageSize ||
+            *init_res->preferredMessageSize > *req->preferredMessageSize)
+            *init_res->preferredMessageSize = *req->preferredMessageSize;
+
+        if (!m_maximumRecordSize ||
+            *init_res->maximumRecordSize > *req->maximumRecordSize)
+            *init_res->maximumRecordSize = *req->maximumRecordSize;
+
+        package.response() = init_response;
+        if (!*response_gdu->u.z3950->u.initResponse->result)
             package.session().close();
-        }
-        else
-        {
-            yazpp_1::GDU init_response = bc->m_init_response;
-            Z_GDU *response_gdu = init_response.get();
-            mp::util::transfer_referenceId(odr, gdu->u.z3950,
-                                           response_gdu->u.z3950);
-
-            Z_Options *server_options =
-                response_gdu->u.z3950->u.initResponse->options;
-            Z_Options *client_options = &frontend->m_init_options;
-
-            int i;
-            for (i = 0; i < 30; i++)
-                if (!ODR_MASK_GET(client_options, i))
-                    ODR_MASK_CLEAR(server_options, i);
-            package.response() = init_response;
-        }
     }
-    if (backend)
-        bc->release_backend(backend);
+    else
+    {
+        Z_APDU *apdu =
+            odr.create_initResponse(
+                gdu->u.z3950, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
+                "session_shared: target closed connection during init");
+        *apdu->u.initResponse->result = 0;
+        package.response() = apdu;
+        package.session().close();
+    }
 }
 
 void yf::SessionShared::BackendSet::timestamp()
@@ -566,15 +600,17 @@ bool yf::SessionShared::BackendSet::search(
         return true;
     }
     Z_APDU *f_apdu = 0;
+    const char *addinfo = "session_shared: "
+        "target closed connection during search";
     if (frontend_apdu->which == Z_APDU_searchRequest)
         f_apdu = odr.create_searchResponse(
-            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, 0);
+            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
     else if (frontend_apdu->which == Z_APDU_presentRequest)
         f_apdu = odr.create_presentResponse(
-            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, 0);
+            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
     else
         f_apdu = odr.create_close(
-            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, 0);
+            frontend_apdu, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, addinfo);
     frontend_package.response() = f_apdu;
     return false;
 }
@@ -692,6 +728,8 @@ restart:
 
             if (out_of_sessions)
                 addinfo = "session_shared: all sessions in use";
+            else
+                addinfo = "session_shared: could not create backend";
             if (apdu_req->which == Z_APDU_searchRequest)
             {
                 f_apdu = odr.create_searchResponse(
@@ -972,7 +1010,8 @@ void yf::SessionShared::Frontend::present(mp::Package &package,
         bc->remove_backend(found_backend);
         Z_APDU *f_apdu_res =
             odr.create_presentResponse(
-                apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, 0);
+                apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
+                "session_shared: target closed connection during present");
         package.response() = f_apdu_res;
     }
 }
@@ -986,7 +1025,8 @@ void yf::SessionShared::Frontend::scan(mp::Package &frontend_package,
     {
         mp::odr odr;
         Z_APDU *apdu = odr.create_scanResponse(
-            apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR, 0);
+            apdu_req, YAZ_BIB1_TEMPORARY_SYSTEM_ERROR,
+            "session_shared: could not create backend");
         frontend_package.response() = apdu;
     }
     else
@@ -1052,7 +1092,13 @@ void yf::SessionShared::Rep::expire()
     while (true)
     {
         boost::xtime xt;
-        boost::xtime_get(&xt, boost::TIME_UTC);
+        boost::xtime_get(&xt,
+#if BOOST_VERSION >= 105000 
+                boost::TIME_UTC_
+#else
+                boost::TIME_UTC
+#endif
+                  );
         xt.sec += m_session_ttl / 3;
         boost::thread::sleep(xt);
 
@@ -1070,6 +1116,8 @@ yf::SessionShared::Rep::Rep()
     m_optimize_search = true;
     m_restart = false;
     m_session_max = 100;
+    m_preferredMessageSize = 0;
+    m_maximumRecordSize = 0;
 }
 
 void yf::SessionShared::Rep::start()
@@ -1258,6 +1306,24 @@ void yf::SessionShared::configure(const xmlNode *ptr, bool test_only,
                                                        attr->name));
             }
         }
+        else if (!strcmp((const char *) ptr->name, "init"))
+        {
+            const struct _xmlAttr *attr;
+            for (attr = ptr->properties; attr; attr = attr->next)
+            {
+                if (!strcmp((const char *) attr->name, "maximum-record-size"))
+                    m_p->m_maximumRecordSize =
+                        mp::xml::get_int(attr->children, 0);
+                else if (!strcmp((const char *) attr->name,
+                                 "preferred-message-size"))
+                    m_p->m_preferredMessageSize =
+                        mp::xml::get_int(attr->children, 0);
+                else
+                    throw mp::filter::FilterException(
+                        "Bad attribute " + std::string((const char *)
+                                                       attr->name));
+            }
+        }
         else
         {
             throw mp::filter::FilterException("Bad element "