Implemented 'block' option to 'show' function to reduce need for
authorSebastian Hammer <quinn@indexdata.com>
Sun, 17 Dec 2006 13:42:47 +0000 (13:42 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Sun, 17 Dec 2006 13:42:47 +0000 (13:42 +0000)
polling after a search. Implemented in 'test1' interface.

PROTOCOL
TODO
http_command.c
pazpar2.c
www/test1/index.html

index 62bd822..d545df4 100644 (file)
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -87,6 +87,11 @@ parameters:
 session
 start      -- 0-indexed!!
 num        -- default=20
+block      -- 0 or 1
+
+If block is set, the command will hang until there are records ready
+to display. Use this to show first records rapidly without requiring rapid
+polling.
 
 Example:
 
diff --git a/TODO b/TODO
index 096e8e3..b9d6dd0 100644 (file)
--- a/TODO
+++ b/TODO
@@ -9,8 +9,6 @@ Factor Z39.50 stuff out from pazpar2.c to separate file to make room for
    later SRU implementation.
 Sort by title, date, author. Parameter to 'show' webservice command.
 Additional facets. At least do 'author'.. think about making it general. -- libxml
-Support for 'blocking' requests, at least for record display before first records
-   are retrieved (to reduce polling).
 Implement detection of 'search complete', so client knows when to stop polling.
 Full record retrieval. -- libxml
 Implement hitsbytarget function to emulate traditional LOT-style U/I
index 194cb8c..d3939dc 100644 (file)
@@ -1,5 +1,5 @@
-/*_response(c, rs);
- * $Id: http_command.c,v 1.8 2006-12-12 02:36:24 quinn Exp $
+/*
+ * $Id: http_command.c,v 1.9 2006-12-17 13:42:47 quinn Exp $
  */
 
 #include <stdio.h>
@@ -26,7 +26,7 @@ extern IOCHAN channel_list;
 struct http_session {
     IOCHAN timeout_iochan;     // NOTE: This is NOT associated with a socket
     struct session *psession;
-    int session_id;
+    unsigned int session_id;
     int timestamp;
     struct http_session *next;
 };
@@ -86,17 +86,17 @@ static void error(struct http_response *rs, char *code, char *msg, char *txt)
     http_send_response(c);
 }
 
-int make_sessionid()
+unsigned int make_sessionid()
 {
     struct timeval t;
-    int res;
+    unsigned int res;
     static int seq = 0;
 
     seq++;
     if (gettimeofday(&t, 0) < 0)
         abort();
     res = t.tv_sec;
-    res = (res << 8) | (seq & 0xff);
+    res = ((res << 8) | (seq & 0xff)) & ((unsigned int) (1 << 31) - 1);
     return res;
 }
 
@@ -104,7 +104,7 @@ static struct http_session *locate_session(struct http_request *rq, struct http_
 {
     struct http_session *p;
     char *session = http_argbyname(rq, "session");
-    int id;
+    unsigned int id;
 
     if (!session)
     {
@@ -131,16 +131,15 @@ static void cmd_exit(struct http_channel *c)
 
 static void cmd_init(struct http_channel *c)
 {
-    int sesid;
+    unsigned int sesid;
     char buf[1024];
     struct http_session *s = http_session_create();
     struct http_response *rs = c->response;
 
-    // FIXME create a pazpar2 session
     yaz_log(YLOG_DEBUG, "HTTP Session init");
     sesid = make_sessionid();
     s->session_id = sesid;
-    sprintf(buf, "<init><status>OK</status><session>%d</session></init>", sesid);
+    sprintf(buf, "<init><status>OK</status><session>%u</session></init>", sesid);
     rs->payload = nmem_strdup(c->nmem, buf);
     http_send_response(c);
 }
@@ -208,7 +207,7 @@ static void cmd_bytarget(struct http_channel *c)
     http_send_response(c);
 }
 
-static void cmd_show(struct http_channel *c)
+static void show_records(struct http_channel *c)
 {
     struct http_request *rq = c->request;
     struct http_response *rs = c->response;
@@ -258,6 +257,36 @@ static void cmd_show(struct http_channel *c)
     http_send_response(c);
 }
 
+static void show_records_ready(void *data)
+{
+    struct http_channel *c = (struct http_channel *) data;
+
+    show_records(c);
+}
+
+static void cmd_show(struct http_channel *c)
+{
+    struct http_request *rq = c->request;
+    struct http_response *rs = c->response;
+    struct http_session *s = locate_session(rq, rs);
+    char *block = http_argbyname(rq, "block");
+
+    if (!s)
+        return;
+
+    if (block)
+    {
+        if (!s->psession->reclist || !s->psession->reclist->num_records)
+        {
+            session_set_watch(s->psession, SESSION_WATCH_RECORDS, show_records_ready, c);
+            yaz_log(YLOG_DEBUG, "Blocking on cmd_show");
+            return;
+        }
+    }
+
+    show_records(c);
+}
+
 static void cmd_ping(struct http_channel *c)
 {
     struct http_request *rq = c->request;
index 55dabb2..1c43633 100644 (file)
--- a/pazpar2.c
+++ b/pazpar2.c
@@ -1,4 +1,4 @@
-/* $Id: pazpar2.c,v 1.13 2006-12-14 14:58:03 quinn Exp $ */;
+/* $Id: pazpar2.c,v 1.14 2006-12-17 13:42:47 quinn Exp $ */;
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -33,8 +33,9 @@ static void client_fatal(struct client *cl);
 static void connection_destroy(struct connection *co);
 static int client_prep_connection(struct client *cl);
 static void ingest_records(struct client *cl, Z_Records *r);
+void session_alert_watch(struct session *s, int what);
 
-IOCHAN channel_list = 0;  // Master list of connections we're listening to.
+IOCHAN channel_list = 0;  // Master list of connections we're handling events to
 
 static struct connection *connection_freelist = 0;
 static struct client *client_freelist = 0;
@@ -638,6 +639,7 @@ static struct record *ingest_record(struct client *cl, char *buf, int len)
 static void ingest_records(struct client *cl, Z_Records *r)
 {
     struct record *rec;
+    struct session *s = cl->session;
     Z_NamePlusRecordList *rlist;
     int i;
 
@@ -669,6 +671,8 @@ static void ingest_records(struct client *cl, Z_Records *r)
         if (!rec)
             continue;
     }
+    if (s->watchlist[SESSION_WATCH_RECORDS].fun && rlist->num_records)
+        session_alert_watch(s, SESSION_WATCH_RECORDS);
 }
 
 static void do_presentResponse(IOCHAN i, Z_APDU *a)
@@ -1121,6 +1125,15 @@ void session_set_watch(struct session *s, int what, session_watchfun fun, void *
     s->watchlist[what].data = data;
 }
 
+void session_alert_watch(struct session *s, int what)
+{
+    if (!s->watchlist[what].fun)
+        return;
+    (*s->watchlist[what].fun)(s->watchlist[what].data);
+    s->watchlist[what].fun = 0;
+    s->watchlist[what].data = 0;
+}
+
 // This should be extended with parameters to control selection criteria
 // Associates a set of clients with a session;
 int select_targets(struct session *se)
index 23a3c89..a79bc68 100644 (file)
@@ -103,7 +103,7 @@ function show_records()
     var xml = xshow.responseXML;
     var body = document.getElementById("body");
     var hits = xml.getElementsByTagName("hit");
-    if (!hits[0])
+    if (!hits[0]) // We should never get here with blocking operations
     {
        body.innerHTML = "No records yet";
        searchtimer = setTimeout(check_search, 250);
@@ -141,12 +141,12 @@ function show_records()
        }
        shown++;
        if (shown < 5)
-           searchtimer = setTimeout(check_search, 400);
-       else if (shown < 10)
            searchtimer = setTimeout(check_search, 1000);
        else
-           searchtimer = setTimeout(check_search, 4000);
+           searchtimer = setTimeout(check_search, 2000);
     }
+    if (!termtimer)
+       termtimer = setTimeout(check_termlist, 1000);
 }
 
 function check_search()
@@ -155,7 +155,8 @@ function check_search()
     var url = "search.pz2?" +
         "command=show" +
        "&start=" + startrec +
-       "&session=" + session;
+       "&session=" + session +
+       "&block=1";
     xshow = GetXmlHttpObject();
     xshow.onreadystatechange=show_records;
     xshow.open("GET", url);
@@ -270,17 +271,20 @@ function search_started()
        alert(msg);
        return;
     }
-    searchtimer = setTimeout(check_search, 250);
-    termtimer = setTimeout(check_termlist, 1000);
+    check_search();
     stattimer = setTimeout(check_stat, 1000);
 }
 
 function start_search()
 {
     clearTimeout(termtimer);
+    termtimer = 0;
     clearTimeout(searchtimer);
+    searchtimer = 0;
     clearTimeout(stattimer);
+    stattimer = 0;
     clearTimeout(showtimer);
+    showtimer = 0;
     if (!targets_loaded)
     {
        alert("Please load targets first");