Happy new year
[pazpar2-moved-to-github.git] / src / session.c
index e67cd10..f597d7c 100644 (file)
@@ -113,7 +113,7 @@ static int session_use(int delta)
     return sessions;
 }
 
-int sessions_count(void)
+int sessions_get_count(void)
 {
     return session_use(0);
 }
@@ -203,13 +203,75 @@ static void session_normalize_facet(struct session *s,
     run_icu(s, icu_chain_id, value, facet_wrbuf, display_wrbuf);
 }
 
-void add_facet(struct session *s, const char *type, const char *value, int count)
+struct facet_id {
+    char *client_id;
+    char *type;
+    char *id;
+    char *term;
+    struct facet_id *next;
+};
+
+static void session_add_id_facet(struct session *s, struct client *cl,
+                                 const char *type,
+                                 const char *id,
+                                 size_t id_len,
+                                 const char *term)
+{
+    struct facet_id *t = nmem_malloc(s->session_nmem, sizeof(*t));
+
+    t->client_id = nmem_strdup(s->session_nmem, client_get_id(cl));
+    t->type = nmem_strdup(s->session_nmem, type);
+    t->id = nmem_strdupn(s->session_nmem, id, id_len);
+    t->term = nmem_strdup(s->session_nmem, term);
+    t->next = s->facet_id_list;
+    s->facet_id_list = t;
+}
+
+
+// Look up a facet term, and return matching id
+// If facet type not found, returns 0
+// If facet type found, but no matching term, returns ""
+const char *session_lookup_id_facet(struct session *s, struct client *cl,
+                                    const char *type,
+                                    const char *term)
+{
+    char *retval = 0;
+    struct facet_id *t = s->facet_id_list;
+    for (; t; t = t->next) 
+    {
+        if (!strcmp(client_get_id(cl), t->client_id) &&  !strcmp(t->type, type) )
+        {
+            retval = "";
+            if ( !strcmp(t->term, term))
+            {
+                return t->id;
+            }
+        }
+    }
+    return retval;
+}
+
+void add_facet(struct session *s, const char *type, const char *value, int count, struct client *cl)
 {
     WRBUF facet_wrbuf = wrbuf_alloc();
     WRBUF display_wrbuf = wrbuf_alloc();
+    const char *id = 0;
+    size_t id_len = 0;
 
-    session_normalize_facet(s, type, value, display_wrbuf, facet_wrbuf);
+    /* inspect pz:facetmap:split:name ?? */
+    if (!strncmp(type, "split:", 6))
+    {
+        const char *cp = strchr(value, ':');
+        if (cp)
+        {
+            id = value;
+            id_len = cp - value;
+            value = cp + 1;
+        }
+        type += 6;
+    }
 
+    session_normalize_facet(s, type, value, display_wrbuf, facet_wrbuf);
     if (wrbuf_len(facet_wrbuf))
     {
         struct named_termlist **tp = &s->termlists;
@@ -224,7 +286,10 @@ void add_facet(struct session *s, const char *type, const char *value, int count
             (*tp)->next = 0;
         }
         termlist_insert((*tp)->termlist, wrbuf_cstr(display_wrbuf),
-                        wrbuf_cstr(facet_wrbuf), count);
+                        wrbuf_cstr(facet_wrbuf), id, id_len, count);
+        if (id)
+            session_add_id_facet(s, cl, type, id, id_len,
+                                 wrbuf_cstr(display_wrbuf));
     }
     wrbuf_destroy(facet_wrbuf);
     wrbuf_destroy(display_wrbuf);
@@ -505,7 +570,6 @@ static void select_targets_callback(struct session *se,
         l->next = se->clients_cached;
         se->clients_cached = l;
     }
-    /* set session always. If may be 0 if client is not active */
     client_set_session(cl, se);
 
     l = xmalloc(sizeof(*l));
@@ -554,6 +618,7 @@ static void session_remove_cached_clients(struct session *se)
         client_lock(l->client);
         client_set_session(l->client, 0);
         client_set_database(l->client, 0);
+        client_mark_dead(l->client);
         client_unlock(l->client);
         client_destroy(l->client);
         xfree(l);
@@ -658,7 +723,7 @@ void session_sort(struct session *se, struct reclist_sortparms *sp,
                 break;
         if (sr)
         {
-            session_log(se, YLOG_DEBUG, "session_sort: field=%s increasing=%d type=%d already fetched",
+            session_log(se, YLOG_LOG, "session_sort: field=%s increasing=%d type=%d already fetched",
                         field, increasing, type);
             session_leave(se, "session_sort");
             return;
@@ -676,7 +741,7 @@ void session_sort(struct session *se, struct reclist_sortparms *sp,
         struct client *cl = l->client;
         // Assume no re-search is required.
         client_parse_init(cl, 1);
-        clients_research += client_parse_sort(cl, sp);
+        clients_research += client_parse_sort(cl, sp, 0);
     }
     if (!clients_research || se->clients_starting)
     {
@@ -718,6 +783,7 @@ void session_sort(struct session *se, struct reclist_sortparms *sp,
         }
         session_enter(se, "session_sort");
         se->clients_starting = 0;
+        se->force_position = 0;
         session_leave(se, "session_sort");
     }
 }
@@ -765,9 +831,14 @@ enum pazpar2_error_code session_search(struct session *se,
     int no_working = 0;
     int no_failed_query = 0;
     int no_failed_limit = 0;
+    int no_sortmap = 0;
     struct client_list *l;
 
-    session_log(se, YLOG_DEBUG, "Search");
+    session_log(se, YLOG_LOG, "search query %s", query);
+    if (filter)
+        session_log(se, YLOG_LOG, "search filter %s", filter);
+    if (limit)
+        session_log(se, YLOG_LOG, "search limit %s", limit);
 
     *addinfo = 0;
 
@@ -778,6 +849,7 @@ enum pazpar2_error_code session_search(struct session *se,
         return PAZPAR2_NO_ERROR;
     }
     se->clients_starting = 1;
+    se->force_position = 0;
     session_leave(se, "session_search0");
 
     if (se->settings_modified) {
@@ -818,6 +890,7 @@ enum pazpar2_error_code session_search(struct session *se,
         *addinfo = "limit";
         session_leave(se, "session_search");
         se->clients_starting = 0;
+        session_reset_active_clients(se, 0);
         return PAZPAR2_MALFORMED_PARAMETER_VALUE;
     }
 
@@ -846,12 +919,20 @@ enum pazpar2_error_code session_search(struct session *se,
         else
         {
             client_parse_range(cl, startrecs, maxrecs);
-            client_parse_sort(cl, sp);
+            client_parse_sort(cl, sp, &no_sortmap);
             client_start_search(cl);
             no_working++;
         }
     }
+    session_log(se, YLOG_LOG, "search "
+                "working %d sortmap %d failed-query %d failed-limit %d",
+                no_working, no_sortmap, no_failed_query, no_failed_limit);
     session_enter(se, "session_search2");
+    if (no_working == 1 && no_sortmap == 1)
+    {
+        se->force_position = 1;
+        yaz_log(YLOG_LOG, "force_position=1");
+    }
     se->clients_starting = 0;
     session_leave(se, "session_search2");
     if (no_working == 0)
@@ -972,8 +1053,17 @@ void session_apply_setting(struct session *se, const char *dbname,
 void session_destroy(struct session *se)
 {
     struct session_database *sdb;
-    session_log(se, YLOG_LOG, "destroy");
-    session_use(-1);
+    struct facet_id *t;
+    int sessions_total = session_use(-1);
+    int no_facet_ids = 0;
+
+    for (t = se->facet_id_list; t; t = t->next)
+        no_facet_ids++;
+    session_log(se, YLOG_LOG, "destroy "
+                "session-total %d nmem-op %zd nmem-ses %zd facets-ids %d",
+                sessions_total,
+                nmem_total(se->nmem), nmem_total(se->session_nmem),
+                no_facet_ids);
     session_remove_cached_clients(se);
 
     for (sdb = se->databases; sdb; sdb = sdb->next)
@@ -983,10 +1073,6 @@ void session_destroy(struct session *se)
     reclist_destroy(se->reclist);
     xfree(se->mergekey);
     xfree(se->rank);
-    if (nmem_total(se->nmem))
-        session_log(se, YLOG_DEBUG, "NMEN operation usage %zd", nmem_total(se->nmem));
-    if (nmem_total(se->session_nmem))
-        session_log(se, YLOG_DEBUG, "NMEN session usage %zd", nmem_total(se->session_nmem));
     facet_limits_destroy(se->facet_limits);
     nmem_destroy(se->nmem);
     service_destroy(se->service);
@@ -1004,8 +1090,8 @@ size_t session_get_memory_status(struct session *session) {
 }
 
 
-struct session *new_session(NMEM nmem, struct conf_service *service,
-                            unsigned session_id)
+struct session *session_create(NMEM nmem, struct conf_service *service,
+                               unsigned session_id)
 {
     int i;
     struct session *session = nmem_malloc(nmem, sizeof(*session));
@@ -1027,6 +1113,7 @@ struct session *new_session(NMEM nmem, struct conf_service *service,
     session->clients_cached = 0;
     session->settings_modified = 0;
     session->session_nmem = nmem;
+    session->facet_id_list = 0;
     session->nmem = nmem_create();
     session->databases = 0;
     session->sorted_results = 0;
@@ -1034,6 +1121,7 @@ struct session *new_session(NMEM nmem, struct conf_service *service,
     session->mergekey = 0;
     session->rank = 0;
     session->clients_starting = 0;
+    session->force_position = 0;
 
     for (i = 0; i <= SESSION_WATCH_MAX; i++)
     {
@@ -1043,9 +1131,9 @@ struct session *new_session(NMEM nmem, struct conf_service *service,
     session->normalize_cache = normalize_cache_create();
     session->session_mutex = 0;
     pazpar2_mutex_create(&session->session_mutex, tmp_str);
-    session_log(session, YLOG_LOG, "create");
 
-    session_use(1);
+    i = session_use(1);
+    session_log(session, YLOG_LOG, "create session-total %d", i);
     return session;
 }
 
@@ -1216,7 +1304,6 @@ void perform_termlist(struct http_channel *c, struct session *se,
                         wrbuf_puts(c->wrbuf, "<name>");
                         wrbuf_xmlputs(c->wrbuf, p[i]->display_term);
                         wrbuf_puts(c->wrbuf, "</name>");
-
                         wrbuf_printf(c->wrbuf,
                                      "<frequency>%d</frequency>",
                                      p[i]->frequency);
@@ -1353,6 +1440,7 @@ struct record_cluster **show_range_start(struct session *se,
     struct reclist_sortparms *spp;
     struct client_list *l;
     int i;
+    NMEM nmem_tmp = 0;
 #if USE_TIMING
     yaz_timing_t t = yaz_timing_create();
 #endif
@@ -1374,7 +1462,15 @@ struct record_cluster **show_range_start(struct session *se,
             *approx_hits += client_get_approximation(l->client);
         }
     }
+    if (se->force_position)
+    {
+        nmem_tmp = nmem_create();
+        sp = reclist_parse_sortparms(nmem_tmp, "position:1", 0);
+        assert(sp);
+    }
     reclist_sort(se->reclist, sp);
+    if (nmem_tmp)
+        nmem_destroy(nmem_tmp);
 
     reclist_enter(se->reclist);
     *total = reclist_get_num_records(se->reclist);
@@ -1656,7 +1752,7 @@ static const char *get_mergekey(xmlDoc *doc, xmlNode *root,
     /* generate unique key if none is not generated already or is empty */
     if (wrbuf_len(norm_wr) == 0)
     {
-        wrbuf_printf(norm_wr, "position: %s-%d",
+        wrbuf_printf(norm_wr, "position: %s-%06d",
                      client_get_id(cl), record_no);
     }
     else
@@ -2099,6 +2195,8 @@ static int ingest_to_cluster(struct client *cl,
             if (!value0 || !*value0)
             {
                 const char *empty = yaz_xml_get_prop(n, "empty");
+                if (value0)
+                    xmlFree(value0);
                 if (!empty)
                     continue;
                 wrbuf_puts(wrbuf_disp, (const char *) empty);
@@ -2106,9 +2204,8 @@ static int ingest_to_cluster(struct client *cl,
             else
             {
                 wrbuf_puts(wrbuf_disp, (const char *) value0);
-            }
-            if (value0)
                 xmlFree(value0);
+            }
             ser_md = &service->metadata[md_field_id];
 
             // non-merged metadata
@@ -2382,15 +2479,15 @@ static int ingest_to_cluster(struct client *cl,
                     char year[64];
                     sprintf(year, "%d", rec_md->data.number.max);
 
-                    add_facet(se, (char *) type, year, term_factor);
+                    add_facet(se, (char *) type, year, term_factor, cl);
                     if (rec_md->data.number.max != rec_md->data.number.min)
                     {
                         sprintf(year, "%d", rec_md->data.number.min);
-                        add_facet(se, (char *) type, year, term_factor);
+                        add_facet(se, (char *) type, year, term_factor, cl);
                     }
                 }
                 else
-                    add_facet(se, type, wrbuf_cstr(wrbuf_disp), term_factor);
+                    add_facet(se, type, wrbuf_cstr(wrbuf_disp), term_factor, cl);
             }
         }
         else