Annotation of parser3/src/types/pa_vmemcached.C, revision 1.4
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.4 ! moko 16: volatile const char * IDENT_PA_VMEMCACHED_C="$Id: pa_vmemcached.C,v 1.3 2012-03-27 10:43:51 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:
24: void error(const char *step, memcached_st* m, memcached_return rc) {
25: const char* str=f_memcached_strerror(m, rc);
26: throw Exception("memcached", 0, "%s error: %s (%d)", step, str ? str : "<unknown>", rc);
27: }
28:
1.2 moko 29: inline void check(const char *action, memcached_st* m, memcached_return rc) {
1.1 moko 30: if(rc==MEMCACHED_SUCCESS)
31: return;
1.2 moko 32: error(action, m, rc);
1.1 moko 33: }
34:
1.2 moko 35: void VMemcached::open(const String& connect_string, time_t attl){
1.1 moko 36: const char *library = memcached_library;
37: const char *memcached_status = memcached_load(library);
38:
39: if(memcached_status)
40: throw Exception("memcached", 0, "failed to load memcached library %s: %s", library, memcached_status);
41:
42: if(connect_string.is_empty())
43: throw Exception("memcached", 0, "server name must not be empty");
44:
1.2 moko 45: fttl=attl;
1.1 moko 46:
47: fm=f_memcached_create(NULL);
48:
49: memcached_server_st* fservers = f_memcached_servers_parse(connect_string.cstr());
50: check("server_push", fm, f_memcached_server_push(fm, fservers));
51: }
52:
1.2 moko 53: void VMemcached::flush(time_t attl){
54: check("flush", fm, f_memcached_flush(fm, attl));
55: }
56:
1.1 moko 57: void VMemcached::remove(const String& aname){
58: if(aname.is_empty())
59: throw Exception("memcached", 0, "key must not be empty");
60: const char* key_cstr=aname.cstr();
61:
62: memcached_return rc=f_memcached_delete(fm, key_cstr, strlen(key_cstr), (time_t)0);
63: if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND)
64: error("delete", fm, rc);
65: }
66:
67: Value* VMemcached::get_element(const String& aname) {
68: if(Value *result=VStateless_object::get_element(aname))
69: return result;
70:
1.2 moko 71: if(aname.is_empty())
72: throw Exception("memcached", 0, "key must not be empty");
1.1 moko 73:
74: size_t length;
1.2 moko 75: uint32_t flags;
1.1 moko 76: memcached_return rc;
1.2 moko 77: const char* val=f_memcached_get(fm, aname.cstr(), aname.length(), &length, &flags, &rc);
1.1 moko 78:
79: if(rc==MEMCACHED_SUCCESS)
1.2 moko 80: // we can't use length from memcached as there can be '\0' inside
1.4 ! moko 81: return new VString(*new String(pa_strdup(val, length), String::L_TAINTED));
! 82:
1.2 moko 83: if(rc==MEMCACHED_NOTFOUND)
1.1 moko 84: return new VVoid();
85:
86: error("get", fm, rc);
87: return 0; // calm down compiler
88: }
89:
1.2 moko 90: Value &VMemcached::mget(ArrayString& akeys) {
91: VHash &hresult = *new VHash();
92:
93: size_t kl = akeys.count();
94:
95: if(kl==0)
96: return hresult;
97:
98: const char **keys = new const char *[kl];
1.3 moko 99: size_t *key_lengths = new size_t[kl];
1.2 moko 100:
101: for(int i=0; i<kl; i++){
102: const String *skey = akeys[i];
103: if(skey->is_empty())
104: throw Exception("memcached", 0, "key must not be empty");
105: keys[i] = skey->cstr();
1.3 moko 106: key_lengths[i] = skey->length();
1.2 moko 107: }
108:
1.3 moko 109: check("mget", fm, f_memcached_mget(fm, keys, key_lengths, kl));
1.2 moko 110:
111: memcached_result_st *results=f_memcached_result_create(fm, 0);
112:
1.4 ! moko 113: memcached_return rc;
! 114:
! 115: while(f_memcached_fetch_result(fm, results, &rc) && (rc == MEMCACHED_SUCCESS)){
! 116: const char *hkey = pa_strdup(f_memcached_result_key_value(results), f_memcached_result_key_length(results));
! 117: const char *hvalue = pa_strdup(f_memcached_result_value(results), f_memcached_result_length(results));
! 118: // we can't use length from memcached for String there can be '\0' inside
! 119: hresult.hash().put(hkey, new VString(*new String(hvalue, String::L_TAINTED)));
1.2 moko 120: }
1.4 ! moko 121:
! 122: if (rc != MEMCACHED_END && rc != MEMCACHED_NOTFOUND)
! 123: error("mget", fm, rc);
1.2 moko 124:
1.3 moko 125: delete keys;
126: delete key_lengths;
127:
1.2 moko 128: // f_memcached_result_free(results);
129:
130: return hresult;
131: }
1.1 moko 132:
133: const VJunction* VMemcached::put_element(const String& aname, Value* avalue, bool /*replace*/){
134: if(aname.is_empty())
135: throw Exception("memcached", 0, "key must not be empty");
136:
1.2 moko 137: time_t ttl=fttl;
138: Value* lvalue;
1.1 moko 139:
140: if(HashStringValue* hash=avalue->get_hash()) {
141: if(Value* ttl_value=hash->get(expires_name))
142: ttl=ttl_value->as_int();
143: if(lvalue=hash->get(value_name)){
144: if(lvalue->get_junction())
145: throw Exception("memcached", 0, VALUE_NAME " must not be code");
146: } else
1.2 moko 147: throw Exception("memcached", &aname, "value hash must contain ." VALUE_NAME);
1.1 moko 148: } else {
149: lvalue=avalue;
150: }
151:
152: const char* key=aname.cstr();
1.2 moko 153: size_t key_length=aname.length();
1.1 moko 154:
1.2 moko 155: if(key_length > MEMCACHED_MAX_KEY)
156: throw Exception("memcached", &aname, "key length %d exceeds limit (%d bytes)", key_length, MEMCACHED_MAX_KEY);
1.1 moko 157:
1.2 moko 158: const String &value=avalue->as_string();
1.1 moko 159:
160: check("set", fm, f_memcached_set(
161: fm,
162: key,
1.2 moko 163: key_length,
164: value.cstr(),
165: value.length(),
1.1 moko 166: ttl,
1.2 moko 167: 0));
1.1 moko 168:
169: return PUT_ELEMENT_REPLACED_ELEMENT;
170: }
171:
E-mail: