LP#1652382: handle cases where supplied key is longer than 250 bytes
[OpenSRF.git] / src / libopensrf / osrf_cache.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3 Bill Erickson <highfalutin@gmail.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 */
15
16 #include <opensrf/osrf_cache.h>
17
18 #define MAX_KEY_LEN 250
19
20 static struct memcached_st* _osrfCache = NULL;
21 static time_t _osrfCacheMaxSeconds = -1;
22 static char* _clean_key( const char* );
23
24 int osrfCacheInit( const char* serverStrings[], int size, time_t maxCacheSeconds ) {
25         memcached_server_st *server_pool;
26         memcached_return rc;
27
28         if( !(serverStrings && size > 0) ) return -1;
29         osrfCacheCleanup(); /* in case we've already been init-ed */
30
31         int i;
32         _osrfCache = memcached_create(NULL);
33         _osrfCacheMaxSeconds = maxCacheSeconds;
34
35         for( i = 0; i < size && serverStrings[i]; i++ ) {
36                 /* TODO: modify caller to pass a list of servers all at once */
37                 server_pool = memcached_servers_parse(serverStrings[i]);
38                 rc = memcached_server_push(_osrfCache, server_pool);
39                 if (rc != MEMCACHED_SUCCESS) {
40                         osrfLogError(OSRF_LOG_MARK,
41                                 "Failed to add memcached server: %s - %s",
42                                 serverStrings[i], memcached_strerror(_osrfCache, rc));
43                 }
44         }
45
46         return 0;
47 }
48
49 int osrfCachePutObject( const char* key, const jsonObject* obj, time_t seconds ) {
50         if( !(key && obj) ) return -1;
51         char* s = jsonObjectToJSON( obj );
52         osrfLogInternal( OSRF_LOG_MARK, "osrfCachePut(): Putting object (key=%s): %s", key, s);
53         osrfCachePutString(key, s, seconds);
54         free(s);
55         return 0;
56 }
57
58 char* _clean_key( const char* key ) {
59     char* clean_key = (char*)strdup(key);
60     char* d = clean_key;
61     char* s = clean_key;
62     do while(isspace(*s) || iscntrl(*s)) s++; while(*d++ = *s++);
63     if (strlen(clean_key) > MAX_KEY_LEN) {
64         char *hashed = md5sum(clean_key);
65         clean_key[0] = '\0';
66         strncat(clean_key, "shortened_", 11);
67         strncat(clean_key, hashed, MAX_KEY_LEN);
68         free(hashed);
69     }
70     return clean_key;
71 }
72
73 int osrfCachePutString( const char* key, const char* value, time_t seconds ) {
74         memcached_return rc;
75         if( !(key && value) ) return -1;
76         seconds = (seconds <= 0 || seconds > _osrfCacheMaxSeconds) ? _osrfCacheMaxSeconds : seconds;
77         osrfLogInternal( OSRF_LOG_MARK, "osrfCachePutString(): Putting string (key=%s): %s", key, value);
78
79         char* clean_key = _clean_key( key );
80
81         /* add or overwrite existing key:value pair */
82         rc = memcached_set(_osrfCache, clean_key, strlen(clean_key), value, strlen(value), seconds, 0);
83         if (rc != MEMCACHED_SUCCESS) {
84                 osrfLogError(OSRF_LOG_MARK, "Failed to cache key:value [%s]:[%s] - %s",
85                         key, value, memcached_strerror(_osrfCache, rc));
86         }
87
88         free(clean_key);
89         return 0;
90 }
91
92 jsonObject* osrfCacheGetObject( const char* key, ... ) {
93         size_t val_len;
94         uint32_t flags;
95         memcached_return rc;
96         jsonObject* obj = NULL;
97         if( key ) {
98                 VA_LIST_TO_STRING(key);
99                 char* clean_key = _clean_key( VA_BUF );
100                 const char* data = (const char*) memcached_get(_osrfCache, clean_key, strlen(clean_key), &val_len, &flags, &rc);
101                 free(clean_key);
102                 if (rc != MEMCACHED_SUCCESS) {
103                         osrfLogDebug(OSRF_LOG_MARK, "Failed to get key [%s] - %s",
104                                 VA_BUF, memcached_strerror(_osrfCache, rc));
105                 }
106                 if( data ) {
107                         osrfLogInternal( OSRF_LOG_MARK, "osrfCacheGetObject(): Returning object (key=%s): %s", VA_BUF, data);
108                         obj = jsonParse( data );
109                         return obj;
110                 }
111                 osrfLogDebug(OSRF_LOG_MARK, "No cache data exists with key %s", VA_BUF);
112         }
113         return NULL;
114 }
115
116 char* osrfCacheGetString( const char* key, ... ) {
117         size_t val_len;
118         uint32_t flags;
119         memcached_return rc;
120         if( key ) {
121                 VA_LIST_TO_STRING(key);
122                 char* clean_key = _clean_key( VA_BUF );
123                 char* data = (char*) memcached_get(_osrfCache, clean_key, strlen(clean_key), &val_len, &flags, &rc);
124                 free(clean_key);
125                 if (rc != MEMCACHED_SUCCESS) {
126                         osrfLogDebug(OSRF_LOG_MARK, "Failed to get key [%s] - %s",
127                                 VA_BUF, memcached_strerror(_osrfCache, rc));
128                 }
129                 osrfLogInternal( OSRF_LOG_MARK, "osrfCacheGetString(): Returning object (key=%s): %s", VA_BUF, data);
130                 if(!data) osrfLogDebug(OSRF_LOG_MARK, "No cache data exists with key %s", VA_BUF);
131                 return data;
132         }
133         return NULL;
134 }
135
136
137 int osrfCacheRemove( const char* key, ... ) {
138         memcached_return rc;
139         if( key ) {
140                 VA_LIST_TO_STRING(key);
141                 rc = memcached_delete(_osrfCache, VA_BUF, strlen(VA_BUF), 0 );
142                 if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) {
143                         osrfLogDebug(OSRF_LOG_MARK, "Failed to delete key [%s] - %s",
144                                 VA_BUF, memcached_strerror(_osrfCache, rc));
145                 }
146                 return 0;
147         }
148         return -1;
149 }
150
151
152 int osrfCacheSetExpire( time_t seconds, const char* key, ... ) {
153         if( key ) {
154                 VA_LIST_TO_STRING(key);
155                 jsonObject* o = osrfCacheGetObject( VA_BUF );
156                 //osrfCacheRemove(VA_BUF);
157                 int rc = osrfCachePutObject( VA_BUF, o, seconds );
158                 jsonObjectFree(o);
159                 return rc;
160         }
161         return -1;
162 }
163
164 void osrfCacheCleanup() {
165         if(_osrfCache) {
166                 memcached_free(_osrfCache);
167         }
168 }
169
170