Merge branch 'master' of ssh://git.indexdata.com/home/git/pub/pazpar2
authorDennis Schafroth <dennis@indexdata.com>
Wed, 30 Mar 2011 13:40:36 +0000 (15:40 +0200)
committerDennis Schafroth <dennis@indexdata.com>
Wed, 30 Mar 2011 13:40:36 +0000 (15:40 +0200)
26 files changed:
NEWS
configure.ac
debian/changelog
doc/book.xml
doc/pazpar2.xml
etc/check-pazpar2.sh
etc/server-status-nagios.xsl
etc/services/long_sessions.xml
pazpar2.spec
src/.gitignore
src/Makefile.am
src/http.c
src/http.h
src/http_command.c
src/parameters.h
src/pazpar2.c
src/pazpar2_config.c
src/pazpar2_config.h
src/pazpar2_play.c [new file with mode: 0644]
src/session.c
src/session.h
test/run_pazpar2.sh
test/test_icu.cfg
test/test_icu.urls
test/test_icu_10.res [new file with mode: 0644]
win/makefile

diff --git a/NEWS b/NEWS
index 3ac310e..053cfe5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,30 +1,42 @@
--- 1.5.4 2011/03/08
-- Experiental support for DTIC DADS target  
-- adds dads-pz2.xsl
-- Support for query_syntax (overrides the default for SRU | Z39.50) 
-- Support for extraArgs (ZOOM "extraArgs" option) for targets
-- New commands: status-server and status-session
-
--- 1.5.3 2011/02/18
-- Fix for threaded runs: 
-Client now have a copy of the database URL, 
+--- 1.5.5 2011/03/28
+
+Fix memory leak that occurred for command=termlist&name=xtargets .
+
+Pazpar2 may save HTTP requests. Enabled by option -R.
+
+--- 1.5.4 2011/03/08
+
+Experimental support for DTIC DADS target. New dads-pz2.xsl.
+
+Support for query_syntax (overrides the default for SRU | Z39.50) 
+
+Support for extraArgs (ZOOM "extraArgs" option) for targets
+
+New commands: status-server and status-session
+
+--- 1.5.3 2011/02/18
+
+Fix for threaded runs: Client now have a copy of the database URL, 
 which can used after the database has been release from the client. 
-This makes the logging in the connection idle timeout of the client nicer (no NOURL)
-and should be thread-safe. 
-- tmarc.xsl: 
-Add journal-title-abbrev and full text. 
-- cf.xsl
-New fields: isbn, issn, journaltitle, volume, issue
-- Fix for cmd=record before search.
-- Session Logging clean up
-- Fix: wrong termlist factor when maxrecs is different from 100.
-
--- 1.5.2 2011/01/18
-Fixes: 
-- Missing pz:termlist_term_factor in settings.c messed up pz:preferred
-- Term factor is default enabled but can be diseabled by pz:termlist_term_factor=0
-
--- 1.5.1 2011/01/06
+This makes the logging in the connection idle timeout of the client nicer (no NOURL) and should be thread-safe.  
+
+tmarc.xsl: Add journal-title-abbrev and full text. 
+
+cf.xsl: new fields: isbn, issn, journaltitle, volume, issue
+
+Fix for cmd=record before search.
+
+Session Logging clean up.
+
+Fix wrong termlist factor when maxrecs is different from 100.
+
+--- 1.5.2 2011/01/18
+
+Fix missing pz:termlist_term_factor in settings.c messed up pz:preferred.
+Term factor is default enabled but can be diseabled by
+pz:termlist_term_factor=0
+
+--- 1.5.1 2011/01/06
 
 Add scaling of facet count. Currently always enabled, needs fixing.
 Allow user-defined info for target suffix. This has no meaning in
index 1134eb4..85ec194 100644 (file)
@@ -5,7 +5,7 @@
 
 # Autoconf and automake setup
 AC_PREREQ(2.60)
-AC_INIT([pazpar2],[1.5.4],[pazpar2-help@indexdata.dk])
+AC_INIT([pazpar2],[1.5.5],[pazpar2-help@indexdata.dk])
 
 AC_CONFIG_HEADERS(src/config.h)
 
index ee2b637..31f83d6 100644 (file)
@@ -1,6 +1,12 @@
-pazpar2 (1.5.3-1indexata) unstable; urgency=low
+pazpar2 (1.5.5-1indexdata) unstable; urgency=low
 
-  * Upstrem.
+  * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk>  Mon, 28 Mar 2011 15:42:06 +0200
+
+pazpar2 (1.5.3-1indexdata) unstable; urgency=low
+
+  * Upstream.
 
  -- Dennis Schafroth <dennis@indexdata.com>  Fri, 18 Feb 2011 12:26:12 +0100
 
index d6ec4df..7c9c9d4 100644 (file)
     On a Debian based Apache 2 system, the relevant modules can
     be enabled with:
     <screen>
-     sudo a2enmod proxy_http
+     sudo a2enmod proxy_http proxy_balancer
     </screen>
    </para>
 
index 9e7b662..32b499c 100644 (file)
@@ -35,6 +35,7 @@
    <arg choice="opt"><option>-h <replaceable>ip:port</replaceable></option></arg>
    <arg choice="opt"><option>-l <replaceable>logfile</replaceable></option></arg>
    <arg choice="opt"><option>-p <replaceable>pidfile</replaceable></option></arg>
+   <arg choice="opt"><option>-R <replaceable>recfile</replaceable></option></arg>
    <arg choice="opt"><option>-t</option></arg>
    <arg choice="opt"><option>-u <replaceable>uid</replaceable></option></arg>
    <arg choice="opt"><option>-V</option></arg>
      </para>
     </listitem>
    </varlistentry>
+   <varlistentry>
+    <term><option>-R <replaceable>recfile</replaceable></option></term>
+    <listitem>
+     <para>
+      If this option is given, HTTP requests are logged to file named
+      <replaceable>recfile</replaceable>.
+     </para>
+    </listitem>
+   </varlistentry>
 
    <varlistentry>
     <term><option>-t</option></term>
index c5d97d6..de11de4 100755 (executable)
@@ -63,6 +63,6 @@ if [ "$CRIT_LEVEL" != "" ] ; then
     fi
 fi 
 
-echo "SESSIONS $MSG $SESSIONS ($CLIENTS) | $SESSIONS;$WARN_LEVEL;$CRIT_LEVEL "
+echo "SESSIONS $MSG $SESSIONS ($CLIENTS) [$VIRT,$VIRTUSE,$AREA,$ORDBLKS,$UORDBLKS,$FORDBLKS,$KEEPCOST,$HBLKS,$HBLKHD]   | $SESSIONS;$WARN_LEVEL;$CRIT_LEVEL "
 exit $rc
 
index 56f53fa..9a2b21b 100644 (file)
@@ -8,6 +8,10 @@
       <xsl:apply-templates />
   </xsl:template>
 
+  <xsl:template match="memory">
+      <xsl:apply-templates />
+  </xsl:template>
+
   <xsl:template match="sessions">
     <xsl:text>export SESSIONS=</xsl:text><xsl:value-of select="." />
   </xsl:template>
     <xsl:text>export RESULTSETS=</xsl:text><xsl:value-of select="." />
   </xsl:template>
 
-  <xsl:template match="*">
+  <xsl:template match="arena">
+    <xsl:text>AREA=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="ordblks">
+    <xsl:text>ORDBLKS=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="uordblks">
+    <xsl:text>UORDBLKS=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="fordblks">
+    <xsl:text>FORDBLKS=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="keepcost">
+    <xsl:text>KEEPCOST=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="hblks">
+    <xsl:text>HBLKS=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="hblkhd">
+    <xsl:text>HBLKHD=</xsl:text><xsl:value-of select="." />
   </xsl:template>
 
+  <xsl:template match="virt">
+    <xsl:text>VIRT=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="virtuse">
+    <xsl:text>VIRTUSE=</xsl:text><xsl:value-of select="." />
+  </xsl:template>
+
+  <xsl:template match="*" />
+
 </xsl:stylesheet>
index c431027..175e8da 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<service id="perf_t" xmlns="http://www.indexdata.com/pazpar2/1.0">
+<service id="long" xmlns="http://www.indexdata.com/pazpar2/1.0">
   <timeout session="600" z3950_operation="30" z3950_session="900"/>  
   <settings target="*">
     <set target="localhost:9999/db01" name="pz:name" value="db01"/>
index f20e2e2..142923a 100644 (file)
@@ -1,7 +1,7 @@
 Summary: Metasearcher
 Name: pazpar2
-Version: 1.5.3
-Release: 1
+Version: 1.5.5
+Release: 1indexdata
 License: GPL
 Group: Applications/Internet
 Vendor: Index Data ApS <info@indexdata.dk>
index b810359..1430d65 100644 (file)
@@ -1,5 +1,6 @@
 yaz
 pazpar2
+pazpar2_play
 Makefile
 Makefile.in
 config.h
index 5ff1aa8..c956188 100644 (file)
@@ -1,6 +1,7 @@
 # This file is part of Pazpar2.
 
 sbin_PROGRAMS = pazpar2
+noinst_PROGRAMS = pazpar2_play
 
 EXTRA_DIST = pazpar2.rpm.init pazpar2.rpm.logrotate
 
@@ -34,6 +35,9 @@ libpazpar2_a_SOURCES = pazpar2_config.c pazpar2_config.h eventl.c eventl.h \
 pazpar2_SOURCES = pazpar2.c
 pazpar2_LDADD = libpazpar2.a $(YAZLIB)
 
+pazpar2_play_SOURCES = pazpar2_play.c
+pazpar2_play_LDADD = $(YAZLIB)
+
 test_sel_thread_SOURCES = test_sel_thread.c
 test_sel_thread_LDADD = libpazpar2.a $(YAZLIB)
 
index d93c874..c9cca1d 100644 (file)
@@ -21,6 +21,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <config.h>
 #endif
 
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
 #include <stdio.h>
 #ifdef WIN32
 #include <winsock.h>
@@ -94,18 +98,12 @@ static void http_server_incref(http_server_t hs);
 
 struct http_server
 {
-    struct http_buf *http_buf_freelist;
-    int http_buf_freelist_count;
-    int http_buf_freelist_max;
-
-    struct http_channel *http_channel_freelist;
-    int http_channel_freelist_count;
-    int http_channel_freelist_max;
     YAZ_MUTEX mutex;
     int listener_socket;
     int ref_count;
     http_sessions_t http_sessions;
     struct sockaddr_in *proxy_addr;
+    FILE *record_file;
 };
 
 struct http_channel_observer_s {
@@ -128,18 +126,7 @@ const char *http_lookup_header(struct http_header *header,
 
 static struct http_buf *http_buf_create(http_server_t hs)
 {
-    struct http_buf *r = 0;
-
-    yaz_mutex_enter(hs->mutex);
-    if (hs->http_buf_freelist)
-    {
-        r = hs->http_buf_freelist;
-        hs->http_buf_freelist = hs->http_buf_freelist->next;
-        hs->http_buf_freelist_count--;
-    }
-    yaz_mutex_leave(hs->mutex);
-    if (!r)
-        r = xmalloc(sizeof(struct http_buf));
+    struct http_buf *r = xmalloc(sizeof(*r));
     r->offset = 0;
     r->len = 0;
     r->next = 0;
@@ -148,24 +135,7 @@ static struct http_buf *http_buf_create(http_server_t hs)
 
 static void http_buf_destroy(http_server_t hs, struct http_buf *b)
 {
-    yaz_mutex_enter(hs->mutex);
-    if (hs->http_buf_freelist_max > 0 && hs->http_buf_freelist_count >= hs->http_buf_freelist_max) {
-        xfree(b);
-        while ((b = hs->http_buf_freelist)) {
-            xfree(b);
-            hs->http_buf_freelist = hs->http_buf_freelist->next;
-        }
-        hs->http_buf_freelist_count = 0;
-    }
-    else {
-        b->next = hs->http_buf_freelist;
-        hs->http_buf_freelist = b;
-        hs->http_buf_freelist_count++;
-#if 0 
-        yaz_log(YLOG_DEBUG, "Free %d http buffers on server.", hs->http_buf_freelist_count);
-#endif
-    }
-    yaz_mutex_leave(hs->mutex);
+    xfree(b);
 }
 
 static void http_buf_destroy_queue(http_server_t hs, struct http_buf *b)
@@ -914,7 +884,18 @@ static void http_io(IOCHAN i, int event)
             }
             if (res <= 0)
             {
+#if HAVE_SYS_TIME_H
+                if (hc->http_server->record_file)
+                {
+                    struct timeval tv;
+                    gettimeofday(&tv, 0);
+                    fprintf(hc->http_server->record_file, "%lld %lld %lld 0\n",
+                            (long long) tv.tv_sec, (long long) tv.tv_usec,
+                            (long long) iochan_getfd(i));
+                }
+#endif
                 http_buf_destroy(hc->http_server, htbuf);
+                fflush(hc->http_server->record_file);
                 http_channel_destroy(i);
                 return;
             }
@@ -931,6 +912,22 @@ static void http_io(IOCHAN i, int event)
                     return;
                 // we have a complete HTTP request
                 nmem_reset(hc->nmem);
+#if HAVE_SYS_TIME_H
+                if (hc->http_server->record_file)
+                {
+                    struct timeval tv;
+                    int sz = 0;
+                    struct http_buf *hb;
+                    for (hb = hc->iqueue; hb; hb = hb->next)
+                        sz += hb->len;
+                    gettimeofday(&tv, 0);
+                    fprintf(hc->http_server->record_file, "%lld %lld %lld %d\n",
+                            (long long) tv.tv_sec, (long long) tv.tv_usec,
+                            (long long) iochan_getfd(i), sz);
+                    for (hb = hc->iqueue; hb; hb = hb->next)
+                        fwrite(hb->buf, 1, hb->len, hc->http_server->record_file);
+                }
+ #endif
                 if (!(hc->request = http_parse_request(hc, &hc->iqueue, reqlen)))
                 {
                     yaz_log(YLOG_WARN, "Failed to parse request");
@@ -1117,24 +1114,6 @@ static void http_channel_destroy(IOCHAN i)
 
     http_server = s->http_server; /* save it for destroy (decref) */
 
-    yaz_mutex_enter(s->http_server->mutex);
-    if (s->http_server->http_channel_freelist_max > 0 && s->http_server->http_channel_freelist_count >= s->http_server->http_channel_freelist_max) {
-        while ((s->next = s->http_server->http_channel_freelist)) {
-            nmem_destroy(s->next->nmem);
-            wrbuf_destroy(s->next->wrbuf);
-            xfree(s->next);
-            s->http_server->http_channel_freelist = s->http_server->http_channel_freelist->next;
-        }
-        s->http_server->http_channel_freelist_count = 0;
-    }
-    else {
-        s->next = s->http_server->http_channel_freelist;
-        s->http_server->http_channel_freelist = s;
-        s->http_server->http_channel_freelist_count++;
-        yaz_log(YLOG_DEBUG, "Free %d channels on server.", s->http_server->http_channel_freelist_count);
-    }
-    yaz_mutex_leave(s->http_server->mutex);
-
     http_server_destroy(http_server);
 
 #ifdef WIN32
@@ -1143,6 +1122,9 @@ static void http_channel_destroy(IOCHAN i)
     close(iochan_getfd(i));
 #endif
     iochan_destroy(i);
+    nmem_destroy(s->nmem);
+    wrbuf_destroy(s->wrbuf);
+    xfree(s);
 }
 
 static struct http_channel *http_channel_create(http_server_t hs,
@@ -1151,25 +1133,10 @@ static struct http_channel *http_channel_create(http_server_t hs,
 {
     struct http_channel *r;
 
-    yaz_mutex_enter(hs->mutex);
-    r = hs->http_channel_freelist;
-    if (r) {
-        hs->http_channel_freelist = r->next;
-        hs->http_channel_freelist_count--;
-    }
-    yaz_mutex_leave(hs->mutex);
+    r = xmalloc(sizeof(struct http_channel));
+    r->nmem = nmem_create();
+    r->wrbuf = wrbuf_alloc();
 
-    if (r)
-    {
-        nmem_reset(r->nmem);
-        wrbuf_rewind(r->wrbuf);
-    }
-    else
-    {
-        r = xmalloc(sizeof(struct http_channel));
-        r->nmem = nmem_create();
-        r->wrbuf = wrbuf_alloc();
-    }
     http_server_incref(hs);
     r->http_server = hs;
     r->http_sessions = hs->http_sessions;
@@ -1223,7 +1190,8 @@ static void http_accept(IOCHAN i, int event)
 }
 
 /* Create a http-channel listener, syntax [host:]port */
-int http_init(const char *addr, struct conf_server *server)
+int http_init(const char *addr, struct conf_server *server,
+              const char *record_fname)
 {
     IOCHAN c;
     int l;
@@ -1232,9 +1200,21 @@ int http_init(const char *addr, struct conf_server *server)
     int one = 1;
     const char *pp;
     short port;
+    FILE *record_file = 0;
 
     yaz_log(YLOG_LOG, "HTTP listener %s", addr);
 
+
+    if (record_fname)
+    {
+        record_file = fopen(record_fname, "wb");
+        if (!record_file)
+        {
+            yaz_log(YLOG_FATAL|YLOG_ERRNO, "fopen %s", record_fname);
+            return 1;
+        }
+    }
+
     memset(&myaddr, 0, sizeof myaddr);
     myaddr.sin_family = AF_INET;
     pp = strchr(addr, ':');
@@ -1286,6 +1266,7 @@ int http_init(const char *addr, struct conf_server *server)
 
     server->http_server = http_server_create();
 
+    server->http_server->record_file = record_file;
     server->http_server->listener_socket = l;
 
     c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server");
@@ -1406,15 +1387,7 @@ http_server_t http_server_create(void)
     hs->ref_count = 1;
     hs->http_sessions = 0;
 
-    hs->http_channel_freelist = 0;
-    hs->http_channel_freelist_count = 0;
-    /* Disable max check */
-    hs->http_channel_freelist_max   = 0;
-
-    hs->http_buf_freelist = 0;
-    hs->http_buf_freelist_count = 0;
-    /* Disable max check */
-    hs->http_buf_freelist_max = 0;
+    hs->record_file = 0;
     return hs;
 }
 
@@ -1430,25 +1403,11 @@ void http_server_destroy(http_server_t hs)
 
         if (r == 0)
         {
-            struct http_buf *b = hs->http_buf_freelist;
-            struct http_channel *c = hs->http_channel_freelist;
-            while (b)
-            {
-                struct http_buf *b_next = b->next;
-                xfree(b);
-                b = b_next;
-            }
-            while (c)
-            {
-                struct http_channel *c_next = c->next;
-                nmem_destroy(c->nmem);
-                wrbuf_destroy(c->wrbuf);
-                xfree(c);
-                c = c_next;
-            }
             http_sessions_destroy(hs->http_sessions);
             xfree(hs->proxy_addr);
             yaz_mutex_destroy(&hs->mutex);
+            if (hs->record_file)
+                fclose(hs->record_file);
             xfree(hs);
         }
     }
index 9a00fee..63d8d88 100644 (file)
@@ -104,7 +104,8 @@ void http_mutex_init(struct conf_server *server);
 void http_server_destroy(http_server_t hs);
 
 void http_set_proxyaddr(const char *url, struct conf_server *ser);
-int http_init(const char *addr, struct conf_server *ser);
+int http_init(const char *addr, struct conf_server *ser,
+              const char *record_fname);
 void http_close_server(struct conf_server *ser);
 void http_addheader(struct http_response *r, 
                     const char *name, const char *value);
index 750623a..9d464d6 100644 (file)
@@ -41,6 +41,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "settings.h"
 #include "client.h"
 
+#include <malloc.h>
+
+void print_meminfo(WRBUF wrbuf) {
+#ifdef __GNUC__
+    struct mallinfo minfo;
+    minfo = mallinfo();
+    wrbuf_printf(wrbuf, "  <memory>\n"
+                        "   <arena>%d</arena>\n" 
+                        "   <uordblks>%d</uordblks>\n"
+                        "   <fordblks>%d</fordblks>\n"
+                        "   <ordblks>%d</ordblks>\n"
+                        "   <keepcost>%d</keepcost>\n"
+                        "   <hblks>%d</hblks>\n" 
+                        "   <hblkhd>%d</hblkhd>\n"
+                        "   <virt>%d</virt>\n"
+                        "   <virtuse>%d</virtuse>\n"
+                        "  </memory>\n", 
+                 minfo.arena, minfo.uordblks, minfo.fordblks,minfo.ordblks, minfo.keepcost, minfo.hblks, minfo.hblkhd, minfo.arena + minfo.hblkhd, minfo.uordblks + minfo.hblkhd);
+
+#endif
+}
+
+
 // Update this when the protocol changes
 #define PAZPAR2_PROTOCOL_VERSION "1"
 
@@ -246,7 +269,7 @@ unsigned int make_sessionid(void)
     unsigned int res;
 
     seq++;
-    if (global_parameters.debug_mode)
+    if (global_parameters.predictable_sessions)
         res = seq;
     else
     {
@@ -637,6 +660,7 @@ static void cmd_server_status(struct http_channel *c)
     wrbuf_printf(c->wrbuf, "  <clients>%u</clients>\n",   clients);
     /* Only works if yaz has been compiled with enabling of this */
     wrbuf_printf(c->wrbuf, "  <resultsets>%u</resultsets>\n",resultsets);
+    print_meminfo(c->wrbuf);
 
 /* TODO add all sessions status                         */
 /*    http_sessions_t http_sessions = c->http_sessions; */
@@ -702,11 +726,10 @@ static void cmd_bytarget(struct http_channel *c)
         if (settings && *settings == '1')
         {
             wrbuf_puts(c->wrbuf, "<settings>\n");
-            wrbuf_puts(c->wrbuf, wrbuf_cstr(ht[i].settings_xml));
+            wrbuf_puts(c->wrbuf, ht[i].settings_xml);
             wrbuf_puts(c->wrbuf, "</settings>\n");
         }
         wrbuf_puts(c->wrbuf, "</target>");
-        wrbuf_destroy(ht[i].settings_xml);
     }
 
     wrbuf_puts(c->wrbuf, "</bytarget>");
index 59a1222..3b45497 100644 (file)
@@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 struct parameters {
     int dump_records;
     int debug_mode;
+    int predictable_sessions;
 };
 extern struct parameters global_parameters;
 
index 6680662..fcbbca2 100644 (file)
@@ -35,6 +35,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/options.h>
 #include <yaz/sc.h>
 
+// #define MTRACE
+#ifdef MTRACE
+#include <mcheck.h>
+#endif
+
 static struct conf_config *sc_stop_config = 0;
 
 void child_handler(void *data)
@@ -95,6 +100,7 @@ static int sc_main(
     const char *uid = 0;
     const char *listener_override = 0;
     const char *config_fname = 0;
+    const char *record_fname = 0;
     struct conf_config *config = 0;
     int test_mode = 0;
 
@@ -108,7 +114,7 @@ static int sc_main(
     yaz_log_init_prefix("pazpar2");
     yaz_log_xml_errors(0, YLOG_WARN);
 
-    while ((ret = options("dDf:h:l:p:tu:v:VX", argv, argc, &arg)) != -2)
+    while ((ret = options("dDf:h:l:p:R:tu:v:VX", argv, argc, &arg)) != -2)
     {
        switch (ret)
         {
@@ -131,6 +137,10 @@ static int sc_main(
         case 'p':
             pidfile = arg;
             break;
+        case 'R':
+            record_fname = arg;
+            global_parameters.predictable_sessions = 1;
+            break;
         case 't':
             test_mode = 1;
             break;
@@ -144,6 +154,7 @@ static int sc_main(
             show_version();
         case 'X':
             global_parameters.debug_mode++;
+            global_parameters.predictable_sessions = 1;
             break;
         default:
             fprintf(stderr, "Usage: pazpar2\n"
@@ -153,6 +164,7 @@ static int sc_main(
                     "    -h [host:]port          Listener port\n"
                     "    -l file                 Log to file\n"
                     "    -p pidfile              PID file\n"
+                    "    -R recfile              HTTP recording file\n"
                     "    -t                      Test configuration\n"
                     "    -u uid                  Change user to uid\n"
                     "    -V                      Show version\n"
@@ -197,7 +209,7 @@ static int sc_main(
                     "mode");
             return 1;
         }
-        ret = config_start_listeners(config, listener_override);
+        ret = config_start_listeners(config, listener_override, record_fname);
         if (ret)
             return ret; /* error starting http listener */
         
@@ -222,10 +234,20 @@ int main(int argc, char **argv)
 {
     int ret;
     yaz_sc_t s = yaz_sc_create("pazpar2", "Pazpar2");
+    
+#ifdef MTRACE
+    mtrace();
+#endif
 
     ret = yaz_sc_program(s, argc, argv, sc_main, sc_stop);
 
     yaz_sc_destroy(&s);
+
+#ifdef MTRACE
+    muntrace();
+#endif
+
+
     exit(ret);
 }
 
index 740ac9c..8b94b63 100644 (file)
@@ -1122,7 +1122,8 @@ void config_process_events(struct conf_config *conf)
 }
 
 int config_start_listeners(struct conf_config *conf,
-                           const char *listener_override)
+                           const char *listener_override,
+                           const char *record_fname)
 {
     struct conf_server *ser;
 
@@ -1149,7 +1150,7 @@ int config_start_listeners(struct conf_config *conf,
                 wrbuf_printf(w, "%d", ser->port);
             }
         }
-        r = http_init(wrbuf_cstr(w), ser);
+        r = http_init(wrbuf_cstr(w), ser, record_fname);
         wrbuf_destroy(w);
         if (r)
             return -1;
index 0bb9cbe..60d7793 100644 (file)
@@ -175,7 +175,8 @@ void service_incref(struct conf_service *service);
 void service_destroy(struct conf_service *service);
 
 int config_start_listeners(struct conf_config *conf,
-                           const char *listener_override);
+                           const char *listener_override,
+                           const char *record_fname);
 
 void config_stop_listeners(struct conf_config *conf);
 
diff --git a/src/pazpar2_play.c b/src/pazpar2_play.c
new file mode 100644 (file)
index 0000000..622885a
--- /dev/null
@@ -0,0 +1,251 @@
+/* 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 <time.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <yaz/options.h>
+#include <yaz/log.h>
+#include <yaz/xmalloc.h>
+
+struct con {
+    int fd;
+    long long id;
+    struct con *next;
+};
+
+
+static int run(FILE *inf, struct addrinfo *res)
+{
+    long long tv_sec0 = 0;
+    long long tv_usec0 = 0;
+    struct con *cons = 0;
+
+    while (1)
+    {
+        long long tv_sec1;
+        long long tv_usec1;
+        long long id;
+        int sz, r, c;
+        char req[100];
+        size_t i;
+        struct con **conp;
+        c = fgetc(inf);
+        if (c == EOF)
+            break;
+
+        for (i = 0; c != '\n' && i < (sizeof(req)-2); i++)
+        {
+            req[i] = c;
+            c = fgetc(inf);
+        }
+        req[i] = 0;
+        r = sscanf(req, "%lld %lld %lld %d", &tv_sec1, &tv_usec1, &id, &sz);
+        if (r != 4)
+        {
+            fprintf(stderr, "bad line %s\n", req);
+            return -1;
+        }
+        if (tv_sec0)
+        {
+            struct timeval spec;
+
+            spec.tv_sec = tv_sec1 - tv_sec0;
+            if (tv_usec0 > tv_usec1)
+            {
+                spec.tv_usec = 1000000 + tv_usec1 - tv_usec0;
+                spec.tv_sec--;
+            }
+            else
+                spec.tv_usec = tv_usec1 - tv_usec0;
+            
+            select(0, 0, 0, 0, &spec);
+        }
+        tv_sec0 = tv_sec1;
+        tv_usec0 = tv_usec1;
+        for (conp = &cons; *conp; conp = &(*conp)->next)
+            if ((*conp)->id == id)
+                break;
+        if (!*conp)
+        {
+            struct addrinfo *rp;
+            int r, fd = -1;
+            for (rp = res; rp; rp = rp->ai_next)
+            {
+                fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+                if (fd != -1)
+                    break;
+            }
+            if (fd == -1)
+            {
+                fprintf(stderr, "socket: cannot create\n");
+                return -1;
+            }
+            r = connect(fd, rp->ai_addr, rp->ai_addrlen);
+            if (r)
+            {
+                fprintf(stderr, "socket: cannot connect\n");
+                return -1;
+            }
+
+            *conp = xmalloc(sizeof(**conp));
+            (*conp)->id = id;
+            (*conp)->fd = fd;
+            (*conp)->next = 0;
+        }
+        if (sz == 0)
+        {
+            struct con *c = *conp;
+            *conp = c->next;
+            close(c->fd);
+            xfree(c);
+        }
+        else
+        {
+            size_t cnt = 0;
+            while (cnt < sz)
+            {
+                char buf[1024];
+                ssize_t w;
+                size_t r;
+                size_t toread = sz - cnt;
+
+                if (toread > sizeof(buf))
+                    toread = sizeof(buf);
+                r = fread(buf, 1, toread, inf);
+                if (r != toread)
+                {
+                    fprintf(stderr, "fread truncated. toread=%lld r=%lld\n",
+                            (long long) toread, (long long) r);
+                    return -1;
+                }
+                w = write((*conp)->fd, buf, toread);
+                if (w != toread)
+                {
+                    fprintf(stderr, "write truncated\n");
+                    return -1;
+                }
+                cnt += toread;
+            }
+        }
+    }
+    return 0;
+}
+
+static void usage(void)
+{
+    fprintf(stderr, "Usage: pazpar2_play infile host\n"
+            "    -v level                Set log level\n");
+    exit(1);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *arg;
+    char *host = 0;
+    const char *file = 0;
+    while ((ret = options("v:", argv, argc, &arg)) != -2)
+    {
+       switch (ret)
+        {
+        case 'v':
+            yaz_log_init_level(yaz_log_mask_str(arg));
+            break;
+        case 0:
+            if (!file)
+                file = arg;
+            else if (!host)
+                host = xstrdup(arg);
+            else
+            {
+                usage();
+            }
+            break;
+        default:
+            usage();
+            exit(1);
+       }
+    }
+    if (host && file)
+    {
+        char *port;
+        char *cp;
+        FILE *inf;
+
+        struct addrinfo hints, *res;
+        hints.ai_flags = 0;
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = 0;
+        hints.ai_addrlen        = 0;
+        hints.ai_addr           = NULL;
+        hints.ai_canonname      = NULL;
+        hints.ai_next           = NULL;
+    
+        cp = strchr(host, ':');
+        if (*cp)
+        {
+            *cp = 0;
+            port = cp+1;
+        }
+        else
+        {
+            port = "80";
+        }
+        if (getaddrinfo(host, port, &hints, &res))
+        {
+            fprintf(stderr, "cannot resolve %s:%s\n", host, port);
+            exit(1);
+        }
+
+        inf = fopen(file, "rb");
+        if (!inf)
+        {
+            fprintf(stderr, "cannot open %s\n", file);
+            exit(1);
+        }
+        run(inf, res);
+        fclose(inf);
+    }
+    else
+        usage();
+    return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
index 405d53b..8a3c0f9 100644 (file)
@@ -86,7 +86,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 struct parameters global_parameters = 
 {
     0,   // dump_records
-    0    // debug_mode
+    0,   // debug_mode
+    0,   // predictable sessions
 };
 
 struct client_list {
@@ -859,7 +860,8 @@ struct hitsbytarget *hitsbytarget(struct session *se, int *count, NMEM nmem)
         res[*count].state = client_get_state_str(cl);
         res[*count].connected  = client_get_connection(cl) ? 1 : 0;
         session_settings_dump(se, client_get_database(cl), w);
-        res[*count].settings_xml = w;
+        res[*count].settings_xml = nmem_strdup(nmem, wrbuf_cstr(w));
+        wrbuf_destroy(w);
         (*count)++;
     }
     session_leave(se);
index 6f43d69..fdecbc4 100644 (file)
@@ -143,7 +143,7 @@ struct hitsbytarget {
     int records;
     const char *state;
     int connected;
-    WRBUF settings_xml;
+    char *settings_xml;
 };
 
 struct hitsbytarget *hitsbytarget(struct session *s, int *count, NMEM nmem);
index 33ce05b..ac1521b 100755 (executable)
@@ -57,7 +57,7 @@ URLS=${PREFIX}.urls
 VALGRINDLOG=${PREFIX}_valgrind.log
 
 if test -n "$PAZPAR2_USE_VALGRIND"; then
-    valgrind --leak-check=full --log-file=$VALGRINDLOG ../src/pazpar2 -X -l pazpar2.log -f ${CFG} >extra_pazpar2.log 2>&1 &
+    valgrind --num-callers=30 --show-reachable=yes --leak-check=full --log-file=$VALGRINDLOG ../src/pazpar2 -X -l pazpar2.log -f ${CFG} >extra_pazpar2.log 2>&1 &
 elif test -n "$SKIP_PAZPAR2"; then 
     echo "Skipping pazpar2. Must already be running with correct config!!! " 
 else
index 0aec864..08dd6de 100644 (file)
@@ -38,7 +38,7 @@
     </facet>
     
     <service>
-
+      <timeout session="30" z3950_operation="20" z3950_session="40"/>
       <metadata name="url" merge="unique"/>
       <metadata name="title" brief="yes" sortkey="skiparticle" merge="longest" rank="6"/>
       <metadata name="title-remainder" brief="yes" merge="longest" rank="5"/>
index 11a5dae..2c6a4b5 100644 (file)
@@ -6,4 +6,5 @@ http://localhost:9763/search.pz2?session=1&command=show&start=0&number=1&sort=ti
 http://localhost:9763/search.pz2?session=1&command=show&start=0&number=1&sort=date:0
 http://localhost:9763/search.pz2?session=1&command=show&start=0&number=1&sort=date:1
 http://localhost:9763/search.pz2?session=1&command=termlist&name=author%2Csubject
-http://localhost:9763/search.pz2?session=1&command=show&start=0&number=1
\ No newline at end of file
+http://localhost:9763/search.pz2?session=1&command=show&start=0&number=1
+http://localhost:9763/search.pz2?session=1&command=termlist&name=xtargets
diff --git a/test/test_icu_10.res b/test/test_icu_10.res
new file mode 100644 (file)
index 0000000..00a481a
--- /dev/null
@@ -0,0 +1,12 @@
+<termlist>
+<activeclients>0</activeclients>
+<list name="xtargets">
+<term>
+<id>z3950.indexdata.com/marc</id>
+<name>Index Data MARC test server</name>
+<frequency>10</frequency>
+<state>Client_Idle</state>
+<diagnostic>0</diagnostic>
+</term>
+</list>
+</termlist>
index 729cec2..869e779 100644 (file)
@@ -4,7 +4,7 @@
 DEBUG=0   # 0 for release, 1 for debug
 USE_MANIFEST = 1 # Can be enabled Visual Studio 2005/2008
 PACKAGE_NAME=pazpar2
-PACKAGE_VERSION=1.4.4
+PACKAGE_VERSION=1.5.5
 
 # YAZ
 YAZ_DIR=..\..\yaz