Enable memcahced binary protocol
[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         memcached_behavior_set(c->mc_st, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);
59 #else
60         ZOOM_set_error(c, ZOOM_ERROR_MEMCACHED, "not enabled");
61         return -1;
62 #endif
63     }
64     return 0;
65 }
66
67 void ZOOM_memcached_resultset(ZOOM_resultset r, ZOOM_query q)
68 {
69 #if HAVE_LIBMEMCACHED_MEMCACHED_H
70     ZOOM_connection c = r->connection;
71     r->mc_key = wrbuf_alloc();
72     wrbuf_puts(r->mc_key, "0;");
73     wrbuf_puts(r->mc_key, c->host_port);
74     wrbuf_puts(r->mc_key, ";");
75     if (c->user)
76         wrbuf_puts(r->mc_key, c->user);
77     wrbuf_puts(r->mc_key, ";");
78     if (c->group)
79         wrbuf_puts(r->mc_key, c->group);
80     wrbuf_puts(r->mc_key, ";");
81     if (c->password)
82         wrbuf_sha1_puts(r->mc_key, c->password, 1);
83     wrbuf_puts(r->mc_key, ";");
84     {
85         WRBUF w = wrbuf_alloc();
86         ZOOM_query_get_hash(q, w);
87         wrbuf_sha1_puts(r->mc_key, wrbuf_cstr(w), 1);
88         wrbuf_destroy(w);
89     }
90     wrbuf_puts(r->mc_key, ";");
91     if (r->req_facets)
92         wrbuf_puts(r->mc_key, r->req_facets);
93 #endif
94 }
95
96 void ZOOM_memcached_search(ZOOM_connection c, ZOOM_resultset resultset)
97 {
98 #if HAVE_LIBMEMCACHED_MEMCACHED_H
99     /* TODO: add sorting */
100     if (c->mc_st && resultset->live_set == 0)
101     {
102         size_t v_len;
103         uint32_t flags;
104         memcached_return_t rc;
105         char *v = memcached_get(c->mc_st, wrbuf_buf(resultset->mc_key),
106                                 wrbuf_len(resultset->mc_key),
107                                 &v_len, &flags, &rc);
108         if (v)
109         {
110             ZOOM_Event event;
111             WRBUF w = wrbuf_alloc();
112
113             wrbuf_write(w, v, v_len);
114             free(v);
115             resultset->size = odr_atoi(wrbuf_cstr(w));
116
117             yaz_log(YLOG_LOG, "For key %s got value %s",
118                     wrbuf_cstr(resultset->mc_key), wrbuf_cstr(w));
119
120             wrbuf_destroy(w);
121             event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
122             ZOOM_connection_put_event(c, event);
123             resultset->live_set = 1;
124         }
125     }
126 #endif
127 }
128
129 void ZOOM_memcached_hitcount(ZOOM_connection c, ZOOM_resultset resultset)
130 {
131 #if HAVE_LIBMEMCACHED_MEMCACHED_H
132     if (c->mc_st && resultset->live_set == 0)
133     {
134         uint32_t flags = 0;
135         memcached_return_t rc;
136         time_t expiration = 36000;
137         char str[40];
138
139         sprintf(str, ODR_INT_PRINTF, resultset->size);
140         rc = memcached_set(c->mc_st,
141                            wrbuf_buf(resultset->mc_key),wrbuf_len(resultset->mc_key),
142                            str, strlen(str), expiration, flags);
143         yaz_log(YLOG_LOG, "Store hit count key=%s value=%s rc=%u %s",
144                 wrbuf_cstr(resultset->mc_key), str, (unsigned) rc,
145                 memcached_last_error_message(c->mc_st));
146     }
147 #endif
148 }
149
150 void ZOOM_memcached_add(ZOOM_resultset r, Z_NamePlusRecord *npr,
151                         int pos,
152                         const char *syntax, const char *elementSetName,
153                         const char *schema,
154                         Z_SRW_diagnostic *diag)
155 {
156 #if HAVE_LIBMEMCACHED_MEMCACHED_H
157     if (r->connection->mc_st &&
158         !diag && npr->which == Z_NamePlusRecord_databaseRecord)
159     {
160         WRBUF k = wrbuf_alloc();
161         uint32_t flags = 0;
162         memcached_return_t rc;
163         time_t expiration = 36000;
164         ODR odr = odr_createmem(ODR_ENCODE);
165         char *rec_buf;
166         int rec_len;
167
168         z_NamePlusRecord(odr, &npr, 0, 0);
169         rec_buf = odr_getbuf(odr, &rec_len, 0);
170
171         wrbuf_write(k, wrbuf_buf(r->mc_key), wrbuf_len(r->mc_key));
172         wrbuf_printf(k, ";%d;%s;%s;%s", pos,
173                      syntax ? syntax : "",
174                      elementSetName ? elementSetName : "",
175                      schema ? schema : "");
176         rc = memcached_set(r->connection->mc_st,
177                            wrbuf_buf(k),wrbuf_len(k),
178                            rec_buf, rec_len,
179                            expiration, flags);
180
181         yaz_log(YLOG_LOG, "Store record lkey=%s len=%d rc=%u %s",
182                 wrbuf_cstr(k), rec_len, (unsigned) rc,
183                 memcached_last_error_message(r->connection->mc_st));
184         odr_destroy(odr);
185         wrbuf_destroy(k);
186     }
187 #endif
188 }
189
190 Z_NamePlusRecord *ZOOM_memcached_lookup(ZOOM_resultset r, int pos,
191                                         const char *syntax,
192                                         const char *elementSetName,
193                                         const char *schema)
194 {
195 #if HAVE_LIBMEMCACHED_MEMCACHED_H
196     if (r->connection && r->connection->mc_st)
197     {
198         WRBUF k = wrbuf_alloc();
199         size_t v_len;
200         char *v_buf;
201         uint32_t flags;
202         memcached_return_t rc;
203
204         wrbuf_write(k, wrbuf_buf(r->mc_key), wrbuf_len(r->mc_key));
205         wrbuf_printf(k, ";%d;%s;%s;%s", pos,
206                      syntax ? syntax : "",
207                      elementSetName ? elementSetName : "",
208                      schema ? schema : "");
209
210         yaz_log(YLOG_LOG, "Lookup record %s", wrbuf_cstr(k));
211         v_buf = memcached_get(r->connection->mc_st, wrbuf_buf(k), wrbuf_len(k),
212                               &v_len, &flags, &rc);
213         wrbuf_destroy(k);
214         if (v_buf)
215         {
216             Z_NamePlusRecord *npr = 0;
217
218             odr_setbuf(r->odr, v_buf, v_len, 0);
219             z_NamePlusRecord(r->odr, &npr, 0, 0);
220             free(v_buf);
221             if (npr)
222                 yaz_log(YLOG_LOG, "returned memcached copy");
223             return npr;
224         }
225     }
226 #endif
227     return 0;
228
229 }
230 /*
231  * Local variables:
232  * c-basic-offset: 4
233  * c-file-style: "Stroustrup"
234  * indent-tabs-mode: nil
235  * End:
236  * vim: shiftwidth=4 tabstop=8 expandtab
237  */
238