Added a full record view (not implemented in the test UI yet)
[pazpar2-moved-to-github.git] / src / reclists.c
1 /*
2  * $Id: reclists.c,v 1.5 2007-01-09 22:06:49 quinn Exp $
3  */
4
5 #include <assert.h>
6
7 #if HAVE_CONFIG_H
8 #include <cconfig.h>
9 #endif
10
11 #include <yaz/yaz-util.h>
12
13 #include "pazpar2.h"
14 #include "reclists.h"
15
16 extern struct parameters global_parameters;
17
18 struct reclist_bucket
19 {
20     struct record_cluster *record;
21     struct reclist_bucket *next;
22 };
23
24 struct record_cluster *reclist_read_record(struct reclist *l)
25 {
26     if (l->pointer < l->num_records)
27         return l->flatlist[l->pointer++];
28     else
29         return 0;
30 }
31
32 void reclist_rewind(struct reclist *l)
33 {
34     l->pointer = 0;
35 }
36
37 // Jenkins one-at-a-time hash (from wikipedia)
38 static unsigned int hash(const unsigned char *key)
39 {
40     unsigned int hash = 0;
41
42     while (*key)
43     {
44         hash += *(key++);
45         hash += (hash << 10);
46         hash ^= (hash >> 6);
47     }
48     hash += (hash << 3);
49     hash ^= (hash >> 11);
50     hash += (hash << 15);
51     return hash;
52 }
53
54 struct reclist *reclist_create(NMEM nmem, int numrecs)
55 {
56     int hashsize = 1;
57     struct reclist *res;
58
59     assert(numrecs);
60     while (hashsize < numrecs)
61         hashsize <<= 1;
62     res = nmem_malloc(nmem, sizeof(struct reclist));
63     res->hashtable = nmem_malloc(nmem, hashsize * sizeof(struct reclist_bucket*));
64     bzero(res->hashtable, hashsize * sizeof(struct reclist_bucket*));
65     res->hashtable_size = hashsize;
66     res->nmem = nmem;
67     res->hashmask = hashsize - 1; // Creates a bitmask
68
69     res->num_records = 0;
70     res->flatlist = nmem_malloc(nmem, numrecs * sizeof(struct record_cluster*));
71     res->flatlist_size = numrecs;
72
73     return res;
74 }
75
76 // Insert a record. Return record cluster (newly formed or pre-existing)
77 struct record_cluster *reclist_insert(struct reclist *l, struct record  *record,
78         char *merge_key, int *total)
79 {
80     unsigned int bucket;
81     struct reclist_bucket **p;
82     struct record_cluster *cluster = 0;
83     struct conf_service *service = global_parameters.server->service;
84
85     bucket = hash((unsigned char*) merge_key) & l->hashmask;
86     for (p = &l->hashtable[bucket]; *p; p = &(*p)->next)
87     {
88         // We found a matching record. Merge them
89         if (!strcmp(merge_key, (*p)->record->merge_key))
90         {
91             struct record_cluster *existing = (*p)->record;
92             record->next = existing->records;
93             existing->records = record;
94             cluster = existing;
95             break;
96         }
97     }
98     if (!cluster && l->num_records < l->flatlist_size)
99     {
100         struct reclist_bucket *new =
101             nmem_malloc(l->nmem, sizeof(struct reclist_bucket));
102         struct record_cluster *newc =
103             nmem_malloc(l->nmem, sizeof(struct record_cluster));
104         
105         record->next = 0;
106         new->record = newc;
107         new->next = 0;
108         newc->records = record;
109         newc->merge_key = merge_key;
110         newc->relevance = 0;
111         newc->term_frequency_vec = 0;
112         newc->recid = (*total)++;
113         newc->metadata = 0;
114         newc->metadata = nmem_malloc(l->nmem,
115                 sizeof(struct record_metadata*) * service->num_metadata);
116         bzero(newc->metadata, sizeof(struct record_metadata*) * service->num_metadata);
117
118         *p = new;
119         l->flatlist[l->num_records++] = newc;
120         cluster = newc;
121     }
122     return cluster;
123 }
124
125
126 /*
127  * Local variables:
128  * c-basic-offset: 4
129  * indent-tabs-mode: nil
130  * End:
131  * vim: shiftwidth=4 tabstop=8 expandtab
132  */