Merge branch 'master' into bug_4688
authorAdam Dickmeiss <adam@indexdata.dk>
Thu, 10 Nov 2011 10:05:14 +0000 (11:05 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Thu, 10 Nov 2011 10:05:14 +0000 (11:05 +0100)
19 files changed:
configure.ac
debian/control
etc/settings/opencontent-solr.xml
src/Makefile.am
src/client.c
src/client.h
src/connection.c
src/connection.h
src/database.c
src/database.h
src/getaddrinfo.c [new file with mode: 0644]
src/host.c [new file with mode: 0644]
src/host.h
src/pazpar2_config.h
src/session.c
src/session.h
win/makefile
www/iphone/example_client.js
www/iphone/index.html

index 2580281..2739cf7 100644 (file)
@@ -22,7 +22,7 @@ AC_LANG(C)
 
 AC_C_INLINE
 
-YAZ_INIT([static icu],[4.2.18])
+YAZ_INIT([static icu],[4.2.20])
 if test -z "$YAZLIB"; then
        AC_MSG_ERROR([YAZ development libraries missing])
 fi
index 21e3fd7..9f04b67 100644 (file)
@@ -4,7 +4,7 @@ Priority: extra
 Maintainer: Adam Dickmeiss <adam@indexdata.dk>
 Build-Depends: debhelper (>= 5),
        autotools-dev,
-       libyaz4-dev (>= 4.2.18),
+       libyaz4-dev (>= 4.2.20),
        docbook-xsl,
        libgnutls-dev
 Standards-Version: 3.7.2
index 0e3d3af..1263eee 100644 (file)
@@ -1,4 +1,4 @@
-<settings target="opencontent-solr.index:8984/solr">
+<settings target="ocs-test.indexdata.com/solr/select">
   <set name="pz:name" value="opencontent-solr"/>
   
   <set name="pz:apdulog" value="1"/>
index 55d3ed5..156d677 100644 (file)
@@ -22,7 +22,8 @@ libpazpar2_a_SOURCES = \
        database.c database.h \
        eventl.c eventl.h \
        facet_limit.c facet_limit.h \
-       host.h \
+       getaddrinfo.c \
+       host.c host.h \
        http.c http.h http_command.c \
        incref.c incref.h \
        jenkins_hash.c jenkins_hash.h \
index ac2e01b..4fe301f 100644 (file)
@@ -703,12 +703,37 @@ int client_has_facet(struct client *cl, const char *name)
     return 0;
 }
 
-void client_start_search(struct client *cl, const char *sort_strategy_and_spec,
-                         int increasing)
+static const char *get_strategy_plus_sort(struct client *l, const char *field)
+{
+    struct session_database *sdb = client_get_database(l);
+    struct setting *s;
+
+    const char *strategy_plus_sort = 0;
+    
+    for (s = sdb->settings[PZ_SORTMAP]; s; s = s->next)
+    {
+        char *p = strchr(s->name + 3, ':');
+        if (!p)
+        {
+            yaz_log(YLOG_WARN, "Malformed sortmap name: %s", s->name);
+            continue;
+        }
+        p++;
+        if (!strcmp(p, field))
+        {
+            strategy_plus_sort = s->value;
+            break;
+        }
+    }
+    return strategy_plus_sort;
+}
+
+void client_start_search(struct client *cl)
 {
     struct session_database *sdb = client_get_database(cl);
     struct connection *co = client_get_connection(cl);
     ZOOM_connection link = connection_get_link(co);
+    struct session *se = client_get_session(cl);
     ZOOM_resultset rs;
     const char *opt_piggyback   = session_setting_oneval(sdb, PZ_PIGGYBACK);
     const char *opt_queryenc    = session_setting_oneval(sdb, PZ_QUERYENCODING);
@@ -788,23 +813,39 @@ void client_start_search(struct client *cl, const char *sort_strategy_and_spec,
         
         ZOOM_query_prefix(q, cl->pquery);
     }
-    if (sort_strategy_and_spec &&
-        strlen(sort_strategy_and_spec) < 40 /* spec below */)
-    {
-        char spec[50], *p;
-        strcpy(spec, sort_strategy_and_spec);
-        p = strchr(spec, ':');
-        if (p)
+    if (se->sorted_results)
+    {   /* first entry is current sorting ! */
+        const char *sort_strategy_and_spec =
+            get_strategy_plus_sort(cl, se->sorted_results->field);
+        int increasing = se->sorted_results->increasing;
+        if (sort_strategy_and_spec && strlen(sort_strategy_and_spec) < 40)
         {
-            *p++ = '\0'; /* cut the string in two */
-            while (*p == ' ')
-                p++;
-            if (increasing)
-                strcat(p, " <");
-            else
-                strcat(p, " >");
-            yaz_log(YLOG_LOG, "applying %s %s", spec, p);
-            ZOOM_query_sortby2(q, spec, p);
+            char spec[50], *p;
+            strcpy(spec, sort_strategy_and_spec);
+            p = strchr(spec, ':');
+            if (p)
+            {
+                *p++ = '\0'; /* cut the string in two */
+                while (*p == ' ')
+                    p++;
+                if (increasing)
+                    strcat(p, " <");
+                else
+                    strcat(p, " >");
+                yaz_log(YLOG_LOG, "applying %s %s", spec, p);
+                ZOOM_query_sortby2(q, spec, p);
+            }
+        }
+        else
+        {
+            /* no native sorting.. If this is not the first search, then
+               skip it entirely */
+            if (se->sorted_results->next)
+            {
+                ZOOM_query_destroy(q);
+                client_set_state_nb(cl, Client_Idle);
+                return;
+            }
         }
     }
     rs = ZOOM_connection_search(link, q);
index 0b1d413..275b294 100644 (file)
@@ -77,8 +77,7 @@ int client_prep_connection(struct client *cl,
                            int operation_timeout, int session_timeout,
                            iochan_man_t iochan,
                            const struct timeval *abstime);
-void client_start_search(struct client *cl, const char *sort_strategy_and_spec,
-                         int increasing);
+void client_start_search(struct client *cl);
 void client_set_session(struct client *cl, struct session *se);
 int client_is_active(struct client *cl);
 int client_is_active_preferred(struct client *cl);
index c5a8ab5..1c7d467 100644 (file)
@@ -150,7 +150,7 @@ static void connection_destroy(struct connection *co)
         ZOOM_connection_destroy(co->link);
         iochan_destroy(co->iochan);
     }
-    yaz_log(YLOG_DEBUG, "%p Connection destroy %s", co, co->host->hostport);
+    yaz_log(YLOG_DEBUG, "%p Connection destroy %s", co, co->host->url);
 
     if (co->client)
     {
@@ -183,7 +183,8 @@ static struct connection *connection_create(struct client *cl,
     co->operation_timeout = operation_timeout;
     co->session_timeout = session_timeout;
     
-    connection_connect(co, iochan_man);
+    if (host->ipport)
+        connection_connect(co, iochan_man);
 
     yaz_mutex_enter(host->mutex);
     co->next = co->host->connections;
@@ -367,6 +368,50 @@ static void connection_release(struct connection *co)
     co->client = 0;
 }
 
+void connect_resolver_host(struct host *host, iochan_man_t iochan_man)
+{
+    struct connection *con;
+
+start:
+    yaz_mutex_enter(host->mutex);
+    con = host->connections;
+    while (con)
+    {
+        if (con->state == Conn_Closed)
+        {
+            if (!host->ipport) /* unresolved */
+            {
+                remove_connection_from_host(con);
+                yaz_mutex_leave(host->mutex);
+                connection_destroy(con);
+                goto start;
+                /* start all over .. at some point it will be NULL */
+            }
+            else if (!con->client)
+            {
+                remove_connection_from_host(con);
+                yaz_mutex_leave(host->mutex);
+                connection_destroy(con);
+                /* start all over .. at some point it will be NULL */
+                goto start;
+            }
+            else
+            {
+                yaz_mutex_leave(host->mutex);
+                connection_connect(con, iochan_man);
+                client_start_search(con->client);
+                goto start;
+            }
+        }
+        else
+        {
+            yaz_log(YLOG_LOG, "connect_resolver_host: state=%d", con->state);
+            con = con->next;
+        }
+    }
+    yaz_mutex_leave(host->mutex);
+}
+
 static struct host *connection_get_host(struct connection *con)
 {
     return con->host;
@@ -382,7 +427,6 @@ static int connection_connect(struct connection *con, iochan_man_t iochan_man)
     const char *sru_version = 0;
 
     struct session_database *sdb = client_get_database(con->client);
-    const char *zproxy = session_setting_oneval(sdb, PZ_ZPROXY);
     const char *apdulog = session_setting_oneval(sdb, PZ_APDULOG);
 
     assert(con);
@@ -394,11 +438,19 @@ static int connection_connect(struct connection *con, iochan_man_t iochan_man)
     if ((charset = session_setting_oneval(sdb, PZ_NEGOTIATION_CHARSET)))
         ZOOM_options_set(zoptions, "charset", charset);
     
-    if (zproxy && *zproxy)
+    assert(host->ipport);
+    if (host->proxy)
     {
-        con->zproxy = xstrdup(zproxy);
-        ZOOM_options_set(zoptions, "proxy", zproxy);
+        yaz_log(YLOG_LOG, "proxy=%s", host->ipport);
+        ZOOM_options_set(zoptions, "proxy", host->ipport);
     }
+    else
+    {
+        assert(host->tproxy);
+        yaz_log(YLOG_LOG, "tproxy=%s", host->ipport);
+        ZOOM_options_set(zoptions, "tproxy", host->ipport);
+    }   
+
     if (apdulog && *apdulog)
         ZOOM_options_set(zoptions, "apdulog", apdulog);
 
@@ -420,14 +472,14 @@ static int connection_connect(struct connection *con, iochan_man_t iochan_man)
     {
         char http_hostport[512];
         strcpy(http_hostport, "http://");
-        strcat(http_hostport, host->hostport);
+        strcat(http_hostport, host->url);
+        yaz_log(YLOG_LOG, "SRU connect to : %s", http_hostport);
         ZOOM_connection_connect(con->link, http_hostport, 0);
     }
     else
     {
-        ZOOM_connection_connect(con->link, host->hostport, 0);
+        ZOOM_connection_connect(con->link, host->url, 0);
     }
-    
     con->iochan = iochan_create(-1, connection_handler, 0, "connection_socket");
     con->state = Conn_Connecting;
     iochan_settimeout(con->iochan, con->operation_timeout);
@@ -449,7 +501,9 @@ int client_prep_connection(struct client *cl,
     struct session_database *sdb = client_get_database(cl);
     const char *zproxy = session_setting_oneval(sdb, PZ_ZPROXY);
     const char *url = session_setting_oneval(sdb, PZ_URL);
+    const char *sru = session_setting_oneval(sdb, PZ_SRU);
     struct host *host = 0;
+    int default_port = *sru ? 80 : 210;
 
     if (zproxy && zproxy[0] == '\0')
         zproxy = 0;
@@ -458,10 +512,12 @@ int client_prep_connection(struct client *cl,
         url = sdb->database->id;
 
     host = find_host(client_get_session(cl)->service->server->database_hosts,
-                     url);
+                     url, zproxy, default_port, iochan_man);
 
     yaz_log(YLOG_DEBUG, "client_prep_connection: target=%s url=%s",
             client_get_id(cl), url);
+    if (!host)
+        return 0;
 
     co = client_get_connection(cl);
 
index 6b61047..0aa0f4c 100644 (file)
@@ -33,6 +33,7 @@ struct host;
 void connect_resolver_host(struct host *host, iochan_man_t iochan);
 ZOOM_connection connection_get_link(struct connection *co);
 void connection_continue(struct connection *co);
+void connect_resolver_host(struct host *host, iochan_man_t iochan_man);
 
 #endif
 
index 41e0f06..c933181 100644 (file)
@@ -54,52 +54,6 @@ struct database_criterion {
     struct database_criterion *next;
 };
 
-struct database_hosts {
-    struct host *hosts;
-    YAZ_MUTEX mutex;
-};
-
-// Create a new host structure for hostport
-static struct host *create_host(const char *hostport)
-{
-    struct host *host;
-    char *db_comment;
-
-    host = xmalloc(sizeof(struct host));
-    host->hostport = xstrdup(hostport);
-    db_comment = strchr(host->hostport, '#');
-    if (db_comment)
-        *db_comment = '\0';
-    host->connections = 0;
-    host->mutex = 0;
-
-    pazpar2_mutex_create(&host->mutex, "host");
-
-    yaz_cond_create(&host->cond_ready);
-
-    return host;
-}
-
-struct host *find_host(database_hosts_t hosts, const char *hostport)
-{
-    struct host *p;
-    yaz_mutex_enter(hosts->mutex);
-    for (p = hosts->hosts; p; p = p->next)
-        if (!strcmp(p->hostport, hostport))
-            break;
-    if (!p)
-    {
-        p = create_host(hostport);
-        if (p)
-        {
-            p->next = hosts->hosts;
-            hosts->hosts = p;
-        }
-    }
-    yaz_mutex_leave(hosts->mutex);
-    return p;
-}
-
 struct database *new_database(const char *id, NMEM nmem)
 {
     struct database *db;
@@ -313,34 +267,6 @@ int predef_grep_databases(void *context, struct conf_service *service,
     return i;
 }
 
-database_hosts_t database_hosts_create(void)
-{
-    database_hosts_t p = xmalloc(sizeof(*p));
-    p->hosts = 0;
-    p->mutex = 0;
-    pazpar2_mutex_create(&p->mutex, "database");
-    return p;
-}
-
-void database_hosts_destroy(database_hosts_t *pp)
-{
-    if (*pp)
-    {
-        struct host *p = (*pp)->hosts;
-        while (p)
-        {
-            struct host *p_next = p->next;
-            yaz_mutex_destroy(&p->mutex);
-            yaz_cond_destroy(&p->cond_ready);
-            xfree(p->hostport);
-            xfree(p);
-            p = p_next;
-        }
-        yaz_mutex_destroy(&(*pp)->mutex);
-        xfree(*pp);
-    }
-}
-
 /*
  * Local variables:
  * c-basic-offset: 4
index 1394732..2b0a3fc 100644 (file)
@@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #ifndef DATABASE_H
 #define DATABASE_H
 
-typedef struct database_hosts *database_hosts_t;
 struct session_database;
 struct session;
 struct conf_service;
@@ -33,9 +32,5 @@ int predef_grep_databases(void *context, struct conf_service *service,
 int match_zurl(const char *zurl, const char *pattern);
 struct database *new_database(const char *id, NMEM nmem);
 
-database_hosts_t database_hosts_create(void);
-void database_hosts_destroy(database_hosts_t *);
-
-struct host *find_host(database_hosts_t hosts, const char *hostport);
 
 #endif
diff --git a/src/getaddrinfo.c b/src/getaddrinfo.c
new file mode 100644 (file)
index 0000000..3ca2f4e
--- /dev/null
@@ -0,0 +1,228 @@
+/* This file is part of Pazpar2.
+   Copyright (C) 2006-2011 Index Data
+
+Pazpar2 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
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "sel_thread.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+
+#include <assert.h>
+#include <sys/types.h>
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef WIN32
+#include <winsock.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <yaz/log.h>
+#include <yaz/nmem.h>
+#include <yaz/tcpip.h>
+
+#include "session.h"
+#include "connection.h"
+#include "host.h"
+
+/* Only use a threaded resolver on Unix that offers getaddrinfo.
+   gethostbyname is NOT reentrant.
+ */
+#if HAVE_GETADDRINFO
+#ifndef WIN32
+#define USE_THREADED_RESOLVER 1
+#endif
+#endif
+
+struct work {
+    char *hostport;  /* hostport to be resolved in separate thread */
+    char *ipport;    /* result or NULL if it could not be resolved */
+    struct host *host; /* host that we're dealing with - mother thread */
+    iochan_man_t iochan_man; /* iochan manager */
+};
+
+static int log_level = YLOG_LOG;
+
+void perform_getaddrinfo(struct work *w)
+{
+    int res = 0;
+    char *port;
+#if HAVE_GETADDRINFO
+    struct addrinfo *addrinfo, hints;
+#else
+    struct hostent *hp;
+#endif
+    char *hostport = xstrdup(w->hostport);
+    if ((port = strchr(hostport, ':')))
+        *(port++) = '\0';
+    else
+    {
+        port = "210";
+    }
+
+#if HAVE_GETADDRINFO
+    hints.ai_flags = 0;
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+    hints.ai_addrlen = 0;
+    hints.ai_addr = 0;
+    hints.ai_canonname = 0;
+    hints.ai_next = 0;
+    // This is not robust code. It assumes that getaddrinfo always
+    // returns AF_INET address.
+    if ((res = getaddrinfo(hostport, port, &hints, &addrinfo)))
+    {
+        yaz_log(YLOG_WARN, "Failed to resolve %s %s", 
+                w->hostport, gai_strerror(res));
+    }
+    else
+    {
+        char ipport[128];
+        unsigned char addrbuf[4];
+        assert(addrinfo->ai_family == PF_INET);
+        memcpy(addrbuf, 
+               &((struct sockaddr_in*)addrinfo->ai_addr)->sin_addr.s_addr, 4);
+        sprintf(ipport, "%u.%u.%u.%u:%s",
+                addrbuf[0], addrbuf[1], addrbuf[2], addrbuf[3], port);
+        freeaddrinfo(addrinfo);
+        w->ipport = xstrdup(ipport);
+        yaz_log(log_level, "Resolved %s -> %s", hostport, ipport);
+    }
+#else
+    hp = gethostbyname(hostport);
+    if (!hp)
+    {
+        yaz_log(YLOG_WARN|YLOG_ERRNO, "Failed to resolve %s", hostport);
+    }
+    else
+    {
+        char ipport[128];
+        unsigned char addrbuf[4];
+
+        memcpy(addrbuf, *hp->h_addr_list, 4 * sizeof(unsigned char));
+        sprintf(ipport, "%u.%u.%u.%u:%s",
+                addrbuf[0], addrbuf[1], addrbuf[2], addrbuf[3], port);
+        w->ipport = xstrdup(ipport);
+        yaz_log(log_level, "Resolved %s -> %s", hostport, ipport);
+    }
+#endif
+    xfree(hostport);
+}
+
+static void work_handler(void *vp)
+{
+    struct work *w = vp;
+
+    int sec = 0;  /* >0 for debugging/testing purposes */
+    if (sec)
+    {
+        yaz_log(log_level, "waiting %d seconds", sec);
+#if HAVE_UNISTD_H
+        sleep(sec);
+#endif
+    }
+    perform_getaddrinfo(w);
+}
+
+#if USE_THREADED_RESOLVER
+void iochan_handler(struct iochan *i, int event)
+{
+    sel_thread_t p = iochan_getdata(i);
+
+    if (event & EVENT_INPUT)
+    {
+        struct work *w = sel_thread_result(p);
+        w->host->ipport = w->ipport;
+        connect_resolver_host(w->host, w->iochan_man);
+        xfree(w);
+    }
+}
+
+static sel_thread_t resolver_thread = 0;
+
+static void getaddrinfo_start(iochan_man_t iochan_man)
+{
+    int fd;
+    sel_thread_t p = resolver_thread = 
+        sel_thread_create(work_handler, 0 /* work_destroy */, &fd,
+                          3 /* no of resolver threads */);
+    if (!p)
+    {
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "sel_create_create failed");
+        exit(1);
+    }
+    else
+    {
+        IOCHAN chan = iochan_create(fd, iochan_handler, EVENT_INPUT,
+            "getaddrinfo_socket");
+        iochan_setdata(chan, p);
+        iochan_add(iochan_man, chan);
+    }
+    yaz_log(log_level, "resolver start");
+    resolver_thread = p;
+}
+#endif
+
+int host_getaddrinfo(struct host *host, iochan_man_t iochan_man)
+{
+    struct work *w = xmalloc(sizeof(*w));
+    int use_thread = 0; /* =0 to disable threading entirely */
+
+    w->hostport = host->tproxy ? host->tproxy : host->proxy;
+    w->ipport = 0;
+    w->host = host;
+    w->iochan_man = iochan_man;
+#if USE_THREADED_RESOLVER
+    if (use_thread)
+    {
+        if (resolver_thread == 0)
+            getaddrinfo_start(iochan_man);
+        assert(resolver_thread);
+        sel_thread_add(resolver_thread, w);
+        return 0;
+    }
+#endif
+    perform_getaddrinfo(w);
+    host->ipport = w->ipport;
+    xfree(w);
+    if (!host->ipport)
+        return -1;
+    return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/host.c b/src/host.c
new file mode 100644 (file)
index 0000000..57c6eb6
--- /dev/null
@@ -0,0 +1,153 @@
+/* This file is part of Pazpar2.
+   Copyright (C) 2006-2011 Index Data
+
+Pazpar2 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
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <yaz/log.h>
+#include <yaz/nmem.h>
+
+#include "ppmutex.h"
+#include "session.h"
+#include "host.h"
+
+#include <sys/types.h>
+
+struct database_hosts {
+    struct host *hosts;
+    YAZ_MUTEX mutex;
+};
+
+// Create a new host structure for hostport
+static struct host *create_host(const char *url, const char *proxy,
+                                int default_port,
+                                iochan_man_t iochan_man)
+{
+    struct host *host;
+    char *db_comment;
+
+    host = xmalloc(sizeof(struct host));
+    host->url = xstrdup(url);
+    host->proxy = 0;
+    host->tproxy = 0;
+    if (proxy && *proxy)
+        host->proxy = xstrdup(proxy);
+    else
+    {
+        char *cp;
+        
+        host->tproxy = xmalloc (strlen(url) + 10); /* so we can add :port */
+        strcpy(host->tproxy, url);
+        for (cp = host->tproxy; *cp; cp++)
+            if (strchr("/?#~", *cp))
+            {
+                *cp = '\0';
+                break;
+            }
+        if (!strchr(host->tproxy, ':'))
+            sprintf(cp, ":%d", default_port); /* no port given, add it */
+    }
+
+    db_comment = strchr(host->url, '#');
+    if (db_comment)
+        *db_comment = '\0';
+    host->connections = 0;
+    host->ipport = 0;
+    host->mutex = 0;
+
+    if (host_getaddrinfo(host, iochan_man))
+    {
+        xfree(host->ipport);
+        xfree(host->tproxy);
+        xfree(host->proxy);
+        xfree(host->url);
+        xfree(host);
+        return 0;
+    }
+    pazpar2_mutex_create(&host->mutex, "host");
+
+    yaz_cond_create(&host->cond_ready);
+
+    return host;
+}
+
+struct host *find_host(database_hosts_t hosts, const char *url,
+                       const char *proxy, int port,
+                       iochan_man_t iochan_man)
+{
+    struct host *p;
+    yaz_mutex_enter(hosts->mutex);
+    for (p = hosts->hosts; p; p = p->next)
+        if (!strcmp(p->url, url))
+            break;
+    if (!p)
+    {
+        p = create_host(url, proxy, port, iochan_man);
+        if (p)
+        {
+            p->next = hosts->hosts;
+            hosts->hosts = p;
+        }
+    }
+    yaz_mutex_leave(hosts->mutex);
+    return p;
+}
+
+database_hosts_t database_hosts_create(void)
+{
+    database_hosts_t p = xmalloc(sizeof(*p));
+    p->hosts = 0;
+    p->mutex = 0;
+    pazpar2_mutex_create(&p->mutex, "database");
+    return p;
+}
+
+void database_hosts_destroy(database_hosts_t *pp)
+{
+    if (*pp)
+    {
+        struct host *p = (*pp)->hosts;
+        while (p)
+        {
+            struct host *p_next = p->next;
+            yaz_mutex_destroy(&p->mutex);
+            yaz_cond_destroy(&p->cond_ready);
+            xfree(p->url);
+            xfree(p->ipport);
+            xfree(p);
+            p = p_next;
+        }
+        yaz_mutex_destroy(&(*pp)->mutex);
+        xfree(*pp);
+    }
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 752ca09..d30632f 100644 (file)
@@ -22,15 +22,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include <yaz/mutex.h>
 
+typedef struct database_hosts *database_hosts_t;
+
 /** \brief Represents a host (irrespective of databases) */
 struct host {
-    char *hostport;
+    char *url;      // logical host/database?args ..
+    char *tproxy;   // tproxy address (no Z39.50 UI)
+    char *proxy;    // logical proxy address
+    char *ipport;   // tproxy or proxy resolved
     struct connection *connections; // All connections to this
     struct host *next;
     YAZ_MUTEX mutex;
     YAZ_COND cond_ready;
 };
 
+database_hosts_t database_hosts_create(void);
+void database_hosts_destroy(database_hosts_t *);
+
+struct host *find_host(database_hosts_t hosts, const char *hostport,
+                      const char *proxy, int port, iochan_man_t iochan_man);
+
+int host_getaddrinfo(struct host *host, iochan_man_t iochan_man);
 
 #endif
 
index 403ec16..f5fb27d 100644 (file)
@@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "charsets.h"
 #include "http.h"
 #include "database.h"
+#include "host.h"
 
 enum conf_metadata_type {
     Metadata_type_generic,    // Generic text field
index d811290..cdd588c 100644 (file)
@@ -95,12 +95,6 @@ struct client_list {
     struct client_list *next;
 };
 
-struct session_sorted_results {
-    const char *field;
-    int increasing;
-    struct session_sorted_results *next;
-};
-
 /* session counting (1) , disable client counting (0) */
 static YAZ_MUTEX g_session_mutex = 0;
 static int no_sessions = 0;
@@ -617,31 +611,6 @@ int session_is_preferred_clients_ready(struct session *s)
     return res == 0;
 }
 
-static const char *get_strategy_plus_sort(struct client *l, const char *field)
-{
-    struct session_database *sdb = client_get_database(l);
-    struct setting *s;
-
-    const char *strategy_plus_sort = 0;
-    
-    for (s = sdb->settings[PZ_SORTMAP]; s; s = s->next)
-    {
-        char *p = strchr(s->name + 3, ':');
-        if (!p)
-        {
-            yaz_log(YLOG_WARN, "Malformed sortmap name: %s", s->name);
-            continue;
-        }
-        p++;
-        if (!strcmp(p, field))
-        {
-            strategy_plus_sort = s->value;
-            break;
-        }
-    }
-    return strategy_plus_sort;
-}
-
 void session_sort(struct session *se, const char *field, int increasing)
 {
     struct session_sorted_results *sr;
@@ -673,16 +642,12 @@ void session_sort(struct session *se, const char *field, int increasing)
     for (l = se->clients_active; l; l = l->next)
     {
         struct client *cl = l->client;
-        const char *strategy_plus_sort = get_strategy_plus_sort(cl, field);
-        if (strategy_plus_sort)
-        {
-            struct timeval tval;
-            if (client_prep_connection(cl, se->service->z3950_operation_timeout,
-                                       se->service->z3950_session_timeout,
-                                       se->service->server->iochan_man,
-                                       &tval))
-                client_start_search(cl, strategy_plus_sort, increasing);
-        }
+        struct timeval tval;
+        if (client_prep_connection(cl, se->service->z3950_operation_timeout,
+                                   se->service->z3950_session_timeout,
+                                   se->service->server->iochan_man,
+                                   &tval))
+            client_start_search(cl);
     }
     session_leave(se);
 }
@@ -756,7 +721,6 @@ enum pazpar2_error_code session_search(struct session *se,
     {
         int parse_ret;
         struct client *cl = l->client;
-        const char *strategy_plus_sort = get_strategy_plus_sort(cl, sort_field);
 
         if (prepare_map(se, client_get_database(cl)) < 0)
             continue;
@@ -775,7 +739,7 @@ enum pazpar2_error_code session_search(struct session *se,
                                        se->service->z3950_session_timeout,
                                        se->service->server->iochan_man,
                                        &tval))
-                client_start_search(cl, strategy_plus_sort, increasing);
+                client_start_search(cl);
         }
         else
         {
index 4368026..a819922 100644 (file)
@@ -183,6 +183,7 @@ int ingest_record(struct client *cl, const char *rec, int record_no, NMEM nmem);
 void session_alert_watch(struct session *s, int what);
 void add_facet(struct session *s, const char *type, const char *value, int count);
 
+
 void perform_termlist(struct http_channel *c, struct session *se,
                       const char *name, int num);
 void session_log(struct session *s, int level, const char *fmt, ...)
@@ -192,6 +193,12 @@ void session_log(struct session *s, int level, const char *fmt, ...)
     ;
 #endif
 
+struct session_sorted_results {
+    const char *field;
+    int increasing;
+    struct session_sorted_results *next;
+};
+
 /*
  * Local variables:
  * c-basic-offset: 4
index 7e6b3ea..8caf4e3 100644 (file)
@@ -178,6 +178,8 @@ LNKOPT= $(COMMON_LNK_OPTIONS) $(RELEASE_LNK_OPTIONS) $(LNK_LIBS)
 # Source and object modules
 
 PAZPAR2_OBJS = \
+   "$(OBJDIR)\getaddrinfo.obj" \
+   "$(OBJDIR)\host.obj" \
    "$(OBJDIR)\pazpar2.obj" \
    "$(OBJDIR)\pazpar2_config.obj" \
    "$(OBJDIR)\http.obj" \
index 4fe0836..fb42b3f 100644 (file)
@@ -4,13 +4,18 @@
 // create a parameters array and pass it to the pz2's constructor
 // then register the form submit event with the pz2.search function
 // autoInit is set to true on default
-var usesessions = true;
+var usesessions = false;
 var pazpar2path = '/service-proxy/';
 var showResponseType = '';
+// Facet configuration
 var querys = {'su': '', 'au': '', 'xt': ''};
-var showResponseType = 'json';
+var query_client_server = {'su': 'subject', 'au': 'author', 'xt': 'xtargets'};
+var querys_server = {};
+var useLimit = 1;
+// Fail to get JSON working stabil.
+var showResponseType = 'xml';
 if (document.location.hash == '#pazpar2' || document.location.search.match("useproxy=false")) {
-    usesessions = false;
+    usesessions = true;
     pazpar2path = '/pazpar2/search.pz2';
     showResponseType = 'xml';
 }
@@ -62,11 +67,11 @@ function handleKeyPress(e, formId, focusId)
 
   if(key == 13 || key == 10)  
   {  
-    document.getElementById(formId).submit();  
-    focusElement = document.getElementById(focusId);
-    if (focusElement)
-      focusElement.focus();  
-    return false;  
+      onFormSubmitEventHandler();
+      focusElement = document.getElementById(focusId);
+      if (focusElement)
+         focusElement.focus();  
+      return false;  
   }  
   else  
     return true;  
@@ -256,7 +261,7 @@ function my_onterm(data) {
     termlists.push('<ul>');
     termlists.push('<li><a href="#" onclick="limitOrResetQuery(\'reset_au\',\'All\');return false;">All<a></li>');
     for (var i = 0; i < data.author.length && i < AuthorMax; i++ ) {
-        termlists.push('<li><a href="#" onclick="limitQuery(\'au\', \'' + data.author[i].name +'\');return false;">' 
+        termlists.push('<li><a href="#" onclick="limitOrResetQuery(\'au\', \'' + data.author[i].name +'\');return false;">' 
                             + data.author[i].name 
                             + '  (' 
                             + data.author[i].freq 
@@ -400,16 +405,23 @@ function resetPage()
     totalRec = 0;
 }
 
+function getFacets() {
+    var result = "";
+    for (var key in querys_server) {
+       if (result.length > 0)
+           result += ","
+       result += querys_server[key];
+    }
+    return result;
+}
+
 function triggerSearch ()
 {
-    my_paz.search(document.search.query.value, recPerPage, curSort, curFilter);
-/*
-    , startWith,
+    my_paz.search(document.search.query.value, recPerPage, curSort, curFilter, undefined,
        {
           "limit" : getFacets() 
        }
        );
-*/
 }
 
 function loadSelect ()
@@ -429,6 +441,27 @@ function limitQuery(field, value)
 }
 
 // limit the query after clicking the facet
+function limitQueryServer(field, value)
+{
+    // Check for client field usage
+    var fieldname = query_client_server[field];
+    if (!fieldname) 
+       fieldname = field;      
+    
+    var newQuery = fieldname + '=' + value.replace(",", "\\,").replace("|", "\\,");
+    // Does it already exists?
+    if (querys_server[fieldname]) 
+       querys_server[fieldname] += "," + newQuery;
+    else
+       querys_server[fieldname] = newQuery;
+//  document.search.query.value += newQuery;
+  onFormSubmitEventHandler();
+  showhide("recordview");
+}
+
+
+
+// limit the query after clicking the facet
 function removeQuery (field, value) {
        document.search.query.value.replace(' and ' + field + '="' + value + '"', '');
     onFormSubmitEventHandler();
@@ -437,18 +470,41 @@ function removeQuery (field, value) {
 
 // limit the query after clicking the facet
 function limitOrResetQuery (field, value, selected) {
-       if (field == 'reset_su' || field == 'reset_au') {
-               var reset_field = field.substring(6);
-               document.search.query.value = document.search.query.value.replace(querys[reset_field], '');
-               querys[reset_field] = '';
-           onFormSubmitEventHandler();
-           showhide("recordview");
-       }
-       else 
-               limitQuery(field, value);
+    if (useLimit) {
+       limitOrResetQueryServer(field,value, selected);
+       return ;
+    }
+    if (field == 'reset_su' || field == 'reset_au') {
+       var reset_field = field.substring(6);
+       document.search.query.value = document.search.query.value.replace(querys[reset_field], '');
+       querys[reset_field] = '';
+       onFormSubmitEventHandler();
+       showhide("recordview");
+    }
+    else 
+       limitQuery(field, value);
        //alert("limitOrResetQuerry: query after: " + document.search.query.value);
 }
 
+// limit the query after clicking the facet
+function limitOrResetQueryServer (field, value, selected) {
+    if (field.substring(0,6) == 'reset_') {
+       var clientname = field.substring(6);
+       var fieldname = query_client_server[clientname];
+       if (!fieldname) 
+           fieldname = clientname;     
+       delete querys_server[fieldname];
+       onFormSubmitEventHandler();
+       showhide("recordview");
+    }
+    else 
+       limitQueryServer(field, value);
+       //alert("limitOrResetQuerry: query after: " + document.search.query.value);
+}
+
+
+
+
 // limit by target functions
 function limitTarget (id, name)
 {
index 8a7b3b7..dd565de 100644 (file)
@@ -55,8 +55,8 @@
 -->
      <td width="100%">
       <form id="searchForm" name="search" style="display: none">
-       <input id="query" type="text" onKeyPress="return handleKeyPress(event, 'searchForm')"/>
-       <input id="button" type="submit" value="go" />
+       <input id="query" type="text" onKeyPress="return handleKeyPress(event, 'searchForm')" />
+       <input id="button" type="submit" value="go" /><a id="hidden" href=""></a>
       </form>
      </td>
     </tr>