memcached: take sorting into account for result set key
[yaz-moved-to-github.git] / src / zoom-memcached.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file zoom-memcached.c
7  * \brief Implements query/record caching using memcached
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <assert.h>
14 #include <string.h>
15 #include <errno.h>
16 #include "zoom-p.h"
17
18 #include <yaz/yaz-util.h>
19 #include <yaz/xmalloc.h>
20 #include <yaz/log.h>
21 #include <yaz/diagbib1.h>
22
23 void ZOOM_memcached_init(ZOOM_connection c)
24 {
25 #if HAVE_LIBMEMCACHED_MEMCACHED_H
26     c->mc_st = 0;
27 #endif
28 }
29
30 void ZOOM_memcached_destroy(ZOOM_connection c)
31 {
32 #if HAVE_LIBMEMCACHED_MEMCACHED_H
33     if (c->mc_st)
34         memcached_free(c->mc_st);
35 #endif
36 }
37
38 int ZOOM_memcached_configure(ZOOM_connection c)
39 {
40     const char *val;
41 #if HAVE_LIBMEMCACHED_MEMCACHED_H
42     if (c->mc_st)
43     {
44         memcached_free(c->mc_st);
45         c->mc_st = 0;
46     }
47 #endif
48     val = ZOOM_options_get(c->options, "memcached");
49     if (val && *val)
50     {
51 #if HAVE_LIBMEMCACHED_MEMCACHED_H
52         c->mc_st = memcached(val, strlen(val));
53         if (!c->mc_st)
54         {
55             ZOOM_set_error(c, ZOOM_ERROR_MEMCACHED, val);
56             return -1;
57         }
58 #else
59         ZOOM_set_error(c, ZOOM_ERROR_MEMCACHED, "not enabled");
60         return -1;
61 #endif
62     }
63     return 0;
64 }
65
66 void ZOOM_memcached_resultset(ZOOM_resultset r, ZOOM_query q)
67 {
68 #if HAVE_LIBMEMCACHED_MEMCACHED_H
69     ZOOM_connection c = r->connection;
70     r->mc_key = wrbuf_alloc();
71     wrbuf_puts(r->mc_key, "0;");
72     wrbuf_puts(r->mc_key, c->host_port);
73     wrbuf_puts(r->mc_key, ";");
74     if (c->user)
75         wrbuf_puts(r->mc_key, c->user);
76     wrbuf_puts(r->mc_key, ";");
77     if (c->group)
78         wrbuf_puts(r->mc_key, c->group);
79     wrbuf_puts(r->mc_key, ";");
80     if (c->password)
81         wrbuf_sha1_puts(r->mc_key, c->password, 1);
82     wrbuf_puts(r->mc_key, ";");
83     {
84         WRBUF w = wrbuf_alloc();
85         ZOOM_query_get_hash(q, w);
86         wrbuf_sha1_puts(r->mc_key, wrbuf_cstr(w), 1);
87         wrbuf_destroy(w);
88     }
89     wrbuf_puts(r->mc_key, ";");
90 #endif
91 }
92
93 void ZOOM_memcached_search(ZOOM_connection c, ZOOM_resultset resultset)
94 {
95 #if HAVE_LIBMEMCACHED_MEMCACHED_H
96     /* TODO: add sorting */
97     if (c->mc_st && resultset->live_set == 0)
98     {
99         size_t v_len;
100         uint32_t flags;
101         memcached_return_t rc;
102         char *v = memcached_get(c->mc_st, wrbuf_buf(resultset->mc_key),
103                                 wrbuf_len(resultset->mc_key),
104                                 &v_len, &flags, &rc);
105         if (v)
106         {
107             ZOOM_Event event;
108             WRBUF w = wrbuf_alloc();
109
110             wrbuf_write(w, v, v_len);
111             free(v);
112             resultset->size = odr_atoi(wrbuf_cstr(w));
113
114             yaz_log(YLOG_LOG, "For key %s got value %s",
115                     wrbuf_cstr(resultset->mc_key), wrbuf_cstr(w));
116
117             wrbuf_destroy(w);
118             event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
119             ZOOM_connection_put_event(c, event);
120             resultset->live_set = 1;
121         }
122     }
123 #endif
124 }
125
126 void ZOOM_memcached_hitcount(ZOOM_connection c, ZOOM_resultset resultset)
127 {
128 #if HAVE_LIBMEMCACHED_MEMCACHED_H
129     if (c->mc_st && resultset->live_set == 0)
130     {
131         uint32_t flags = 0;
132         memcached_return_t rc;
133         time_t expiration = 36000;
134         char str[40];
135
136         sprintf(str, ODR_INT_PRINTF, resultset->size);
137         rc = memcached_set(c->mc_st,
138                            wrbuf_buf(resultset->mc_key),wrbuf_len(resultset->mc_key),
139                            str, strlen(str), expiration, flags);
140         yaz_log(YLOG_LOG, "Store hit count key=%s value=%s rc=%u %s",
141                 wrbuf_cstr(resultset->mc_key), str, (unsigned) rc,
142                 memcached_last_error_message(c->mc_st));
143     }
144 #endif
145 }
146
147 void ZOOM_memcached_add(ZOOM_resultset r, Z_NamePlusRecord *npr,
148                         int pos,
149                         const char *syntax, const char *elementSetName,
150                         const char *schema,
151                         Z_SRW_diagnostic *diag)
152 {
153 #if HAVE_LIBMEMCACHED_MEMCACHED_H
154     if (r->connection->mc_st &&
155         !diag && npr->which == Z_NamePlusRecord_databaseRecord)
156     {
157         WRBUF k = wrbuf_alloc();
158         uint32_t flags = 0;
159         memcached_return_t rc;
160         time_t expiration = 36000;
161         ODR odr = odr_createmem(ODR_ENCODE);
162         char *rec_buf;
163         int rec_len;
164
165         z_NamePlusRecord(odr, &npr, 0, 0);
166         rec_buf = odr_getbuf(odr, &rec_len, 0);
167
168         wrbuf_write(k, wrbuf_buf(r->mc_key), wrbuf_len(r->mc_key));
169         wrbuf_printf(k, ";%d;%s;%s;%s", pos,
170                      syntax ? syntax : "",
171                      elementSetName ? elementSetName : "",
172                      schema ? schema : "");
173         rc = memcached_set(r->connection->mc_st,
174                            wrbuf_buf(k),wrbuf_len(k),
175                            rec_buf, rec_len,
176                            expiration, flags);
177
178         yaz_log(YLOG_LOG, "Store record lkey=%s len=%d rc=%u %s",
179                 wrbuf_cstr(k), rec_len, (unsigned) rc,
180                 memcached_last_error_message(r->connection->mc_st));
181         odr_destroy(odr);
182         wrbuf_destroy(k);
183     }
184 #endif
185 }
186
187 Z_NamePlusRecord *ZOOM_memcached_lookup(ZOOM_resultset r, int pos,
188                                         const char *syntax,
189                                         const char *elementSetName,
190                                         const char *schema)
191 {
192 #if HAVE_LIBMEMCACHED_MEMCACHED_H
193     if (r->connection && r->connection->mc_st)
194     {
195         WRBUF k = wrbuf_alloc();
196         size_t v_len;
197         char *v_buf;
198         uint32_t flags;
199         memcached_return_t rc;
200
201         wrbuf_write(k, wrbuf_buf(r->mc_key), wrbuf_len(r->mc_key));
202         wrbuf_printf(k, ";%d;%s;%s;%s", pos,
203                      syntax ? syntax : "",
204                      elementSetName ? elementSetName : "",
205                      schema ? schema : "");
206
207         yaz_log(YLOG_LOG, "Lookup record %s", wrbuf_cstr(k));
208         v_buf = memcached_get(r->connection->mc_st, wrbuf_buf(k), wrbuf_len(k),
209                               &v_len, &flags, &rc);
210         wrbuf_destroy(k);
211         if (v_buf)
212         {
213             Z_NamePlusRecord *npr = 0;
214
215             odr_setbuf(r->odr, v_buf, v_len, 0);
216             z_NamePlusRecord(r->odr, &npr, 0, 0);
217             free(v_buf);
218             if (npr)
219                 yaz_log(YLOG_LOG, "returned memcached copy");
220             return npr;
221         }
222     }
223 #endif
224     return 0;
225
226 }
227 /*
228  * Local variables:
229  * c-basic-offset: 4
230  * c-file-style: "Stroustrup"
231  * indent-tabs-mode: nil
232  * End:
233  * vim: shiftwidth=4 tabstop=8 expandtab
234  */
235