Annotation of parser3/src/types/pa_vmemcached.C, revision 1.8
1.1 moko 1: /** @file
2: Parser: memcached class.
3:
4: Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)
5: Authors:
6: Ivan Poluyanov <ivan-poluyanov@yandex.ru>
7: Artem Stepanov <timofei1394@thesecure.in>
8: */
9:
10: #include "pa_vmemcached.h"
11: #include "pa_value.h"
12: #include "pa_vstring.h"
1.2 moko 13: #include "pa_vhash.h"
1.1 moko 14: #include "pa_vvoid.h"
15:
1.8 ! moko 16: volatile const char * IDENT_PA_VMEMCACHED_C="$Id: pa_vmemcached.C,v 1.7 2012-04-15 23:49:05 moko Exp $" IDENT_PA_VMEMCACHED_H;
1.1 moko 17:
18: #ifdef WIN32
19: const char *memcached_library="libmemcached.dll";
20: #else
21: const char *memcached_library="libmemcached.so";
22: #endif
23:
1.8 ! moko 24: // support functions
! 25:
! 26: static void error(const char *step, memcached_st* m, memcached_return rc) {
1.1 moko 27: const char* str=f_memcached_strerror(m, rc);
28: throw Exception("memcached", 0, "%s error: %s (%d)", step, str ? str : "<unknown>", rc);
29: }
30:
1.2 moko 31: inline void check(const char *action, memcached_st* m, memcached_return rc) {
1.1 moko 32: if(rc==MEMCACHED_SUCCESS)
33: return;
1.2 moko 34: error(action, m, rc);
1.1 moko 35: }
36:
1.6 moko 37: inline void check_key(const String& akey) {
38: if(akey.is_empty())
39: throw Exception("memcached", 0, "key must not be empty");
40: if(akey.length() > MEMCACHED_MAX_KEY)
41: throw Exception("memcached", &akey, "key length %d exceeds limit (%d bytes)", akey.length(), MEMCACHED_MAX_KEY);
42: }
43:
1.8 ! moko 44: // serialization helpers
! 45:
! 46: #define SERIALIZED_STRING 256
! 47:
! 48: struct Serialization_data{
! 49: unsigned int flags;
! 50: const char *ptr;
! 51: size_t length;
! 52:
! 53: Serialization_data() : flags(0), ptr(0), length(0){}
! 54: Serialization_data(unsigned int aflags) : flags(aflags), ptr(0), length(0){}
! 55: Serialization_data(unsigned int aflags, const char *aptr, size_t alength) : flags(aflags), ptr(aptr), length(alength){}
! 56: };
! 57:
! 58: static void serialize_string(const String &str, Serialization_data &data){
! 59: if(str.is_empty()){
! 60: data = Serialization_data(SERIALIZED_STRING);
! 61: return;
! 62: }
! 63:
! 64: if (str.is_not_just_lang()){
! 65: String::Cm cm = str.serialize(0);
! 66: data = Serialization_data(SERIALIZED_STRING, cm.str, cm.length);
! 67: } else {
! 68: data = Serialization_data(SERIALIZED_STRING + (unsigned int)str.just_lang(), str.cstr(), str.length());
! 69: }
! 70: }
! 71:
! 72: static VString *deserialize_string(Serialization_data &data){
! 73: String *result;
! 74:
! 75: if(data.flags==SERIALIZED_STRING){
! 76: result = new String();
! 77: if (data.length>0 && !result->deserialize(0, (void *)data.ptr, data.length))
! 78: return NULL;
! 79: } else {
! 80: // we can't use length from memcached as there can be '\0' inside
! 81: String::Language lang=(String::Language)(data.flags-SERIALIZED_STRING);
! 82: result = new String(data.ptr, lang);
! 83: }
! 84:
! 85: return new VString(*result);
! 86: }
! 87:
! 88: static Value &deserialize(Serialization_data &data){
! 89: Value *result=NULL;
! 90:
! 91: if(data.flags>=SERIALIZED_STRING && data.flags<(SERIALIZED_STRING+256)){
! 92: // String->deserialize uses passed string
! 93: data.ptr=pa_strdup(data.ptr, data.length);
! 94: result=deserialize_string(data);
! 95: }
! 96:
! 97: if (!result)
! 98: throw Exception(PARSER_RUNTIME, 0, "unable to deserialize data id %d, size %d", data.flags, data.length);
! 99:
! 100: return *result;
! 101: }
! 102:
! 103: // VMemcached
! 104:
1.2 moko 105: void VMemcached::open(const String& connect_string, time_t attl){
1.1 moko 106: const char *library = memcached_library;
107: const char *memcached_status = memcached_load(library);
108:
109: if(memcached_status)
110: throw Exception("memcached", 0, "failed to load memcached library %s: %s", library, memcached_status);
111:
112: if(connect_string.is_empty())
113: throw Exception("memcached", 0, "server name must not be empty");
114:
1.2 moko 115: fttl=attl;
1.1 moko 116:
117: fm=f_memcached_create(NULL);
118:
119: memcached_server_st* fservers = f_memcached_servers_parse(connect_string.cstr());
120: check("server_push", fm, f_memcached_server_push(fm, fservers));
121: }
122:
1.6 moko 123: void VMemcached::flush(time_t attl) {
1.2 moko 124: check("flush", fm, f_memcached_flush(fm, attl));
125: }
126:
1.6 moko 127: void VMemcached::remove(const String& aname) {
128: check_key(aname);
129:
130: memcached_return rc=f_memcached_delete(fm, aname.cstr(), aname.length(), (time_t)0);
1.1 moko 131:
132: if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND)
133: error("delete", fm, rc);
134: }
135:
136: Value* VMemcached::get_element(const String& aname) {
137: if(Value *result=VStateless_object::get_element(aname))
138: return result;
139:
1.6 moko 140: check_key(aname);
1.1 moko 141:
142: memcached_return rc;
1.5 moko 143: Serialization_data data;
144: data.ptr=f_memcached_get(fm, aname.cstr(), aname.length(), &data.length, &data.flags, &rc);
1.1 moko 145:
1.5 moko 146: if(rc==MEMCACHED_SUCCESS){
1.8 ! moko 147: return &deserialize(data);
1.5 moko 148: }
1.4 moko 149:
1.2 moko 150: if(rc==MEMCACHED_NOTFOUND)
1.1 moko 151: return new VVoid();
152:
153: error("get", fm, rc);
154: return 0; // calm down compiler
155: }
156:
1.2 moko 157: Value &VMemcached::mget(ArrayString& akeys) {
158: VHash &hresult = *new VHash();
159:
160: size_t kl = akeys.count();
161:
162: if(kl==0)
163: return hresult;
164:
165: const char **keys = new const char *[kl];
1.3 moko 166: size_t *key_lengths = new size_t[kl];
1.2 moko 167:
1.6 moko 168: for(size_t i=0; i<kl; i++){
169: const String &skey = *(akeys[i]);
170: check_key(skey);
171: keys[i] = skey.cstr();
172: key_lengths[i] = skey.length();
1.2 moko 173: }
174:
1.3 moko 175: check("mget", fm, f_memcached_mget(fm, keys, key_lengths, kl));
1.2 moko 176:
1.7 moko 177: // memcached_fetch_result calls memcached_result_create and memcached_result_free, we don't need to do this.
178: memcached_result_st *results=0;
1.4 moko 179: memcached_return rc;
180:
1.7 moko 181: while((results=f_memcached_fetch_result(fm, results, &rc)) && (rc == MEMCACHED_SUCCESS)){
1.4 moko 182: const char *hkey = pa_strdup(f_memcached_result_key_value(results), f_memcached_result_key_length(results));
1.8 ! moko 183: Serialization_data data(f_memcached_result_flags(results), f_memcached_result_value(results), f_memcached_result_length(results));
1.5 moko 184:
1.8 ! moko 185: hresult.hash().put(hkey, &deserialize(data));
1.2 moko 186: }
1.4 moko 187:
188: if (rc != MEMCACHED_END && rc != MEMCACHED_NOTFOUND)
189: error("mget", fm, rc);
1.2 moko 190:
1.3 moko 191: delete keys;
192: delete key_lengths;
193:
1.2 moko 194: return hresult;
195: }
1.1 moko 196:
197: const VJunction* VMemcached::put_element(const String& aname, Value* avalue, bool /*replace*/){
1.6 moko 198: check_key(aname);
1.1 moko 199:
1.2 moko 200: time_t ttl=fttl;
201: Value* lvalue;
1.1 moko 202:
203: if(HashStringValue* hash=avalue->get_hash()) {
204: if(Value* ttl_value=hash->get(expires_name))
205: ttl=ttl_value->as_int();
206: if(lvalue=hash->get(value_name)){
207: if(lvalue->get_junction())
208: throw Exception("memcached", 0, VALUE_NAME " must not be code");
209: } else
1.2 moko 210: throw Exception("memcached", &aname, "value hash must contain ." VALUE_NAME);
1.1 moko 211: } else {
212: lvalue=avalue;
213: }
214:
1.8 ! moko 215: Serialization_data data;
! 216: if(avalue->is_string()){
! 217: serialize_string(*avalue->get_string(), data);
! 218: } else {
! 219: throw Exception("memcached", &aname, "%s serialization not supported yet", avalue->type());
! 220: }
1.1 moko 221:
222: check("set", fm, f_memcached_set(
223: fm,
1.6 moko 224: aname.cstr(),
225: aname.length(),
1.8 ! moko 226: data.ptr,
! 227: data.length,
1.1 moko 228: ttl,
1.8 ! moko 229: data.flags));
1.1 moko 230:
231: return PUT_ELEMENT_REPLACED_ELEMENT;
232: }
233:
E-mail: