Annotation of parser3/src/types/pa_vmemcached.C, revision 1.11

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.11    ! moko       16: volatile const char * IDENT_PA_VMEMCACHED_C="$Id: pa_vmemcached.C,v 1.10 2012-04-22 22:06:50 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
1.9       moko       93:                if(data.length>0)
                     94:                        data.ptr=pa_strdup(data.ptr, data.length);
1.8       moko       95:                result=deserialize_string(data);
                     96:        }
                     97: 
                     98:        if (!result)
                     99:                throw Exception(PARSER_RUNTIME, 0, "unable to deserialize data id %d, size %d", data.flags, data.length);
                    100: 
                    101:        return *result;
                    102: }
                    103: 
                    104: // VMemcached
                    105: 
1.10      moko      106: static void load_memcached(const char *library){
1.1       moko      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);
1.10      moko      111: }
                    112: 
                    113: void VMemcached::open(const String& options_string, time_t attl){
                    114:        load_memcached(memcached_library);
                    115:        
                    116:        if(f_memcached==NULL)
                    117:                throw Exception("memcached", 0, "options hash requires libmemcached version 0.49 or later");
                    118:        
                    119:        if(options_string.is_empty())
                    120:                throw Exception("memcached", 0, "options hash must not be empty");
                    121:        
                    122:        fttl=attl;
                    123:        fm=f_memcached(options_string.cstr(), options_string.length());
                    124: }
1.1       moko      125: 
1.10      moko      126: void VMemcached::open_parse(const String& connect_string, time_t attl){
                    127:        load_memcached(memcached_library);
                    128:        
1.1       moko      129:        if(connect_string.is_empty())
1.10      moko      130:                throw Exception("memcached", 0, "connect string must not be empty");
                    131:        
1.2       moko      132:        fttl=attl;
1.1       moko      133:        fm=f_memcached_create(NULL);
                    134:        memcached_server_st* fservers = f_memcached_servers_parse(connect_string.cstr());
                    135:        check("server_push", fm, f_memcached_server_push(fm, fservers));
                    136: }
                    137: 
1.6       moko      138: void VMemcached::flush(time_t attl) {
1.2       moko      139:        check("flush", fm, f_memcached_flush(fm, attl));
                    140: }
                    141: 
1.6       moko      142: void VMemcached::remove(const String& aname) {
                    143:        check_key(aname);
                    144: 
                    145:        memcached_return rc=f_memcached_delete(fm, aname.cstr(), aname.length(), (time_t)0);
1.1       moko      146: 
                    147:        if(rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND)
                    148:                error("delete", fm, rc);
                    149: }
                    150: 
                    151: Value* VMemcached::get_element(const String& aname) {
                    152:        if(Value *result=VStateless_object::get_element(aname))
                    153:                return result;
                    154: 
1.6       moko      155:        check_key(aname);
1.1       moko      156: 
                    157:        memcached_return rc;
1.5       moko      158:        Serialization_data data;
                    159:        data.ptr=f_memcached_get(fm, aname.cstr(), aname.length(), &data.length, &data.flags, &rc);
1.1       moko      160: 
1.5       moko      161:        if(rc==MEMCACHED_SUCCESS){
1.8       moko      162:                return &deserialize(data);
1.5       moko      163:        }
1.4       moko      164:        
1.2       moko      165:        if(rc==MEMCACHED_NOTFOUND)
1.11    ! moko      166:                return VVoid::get();
1.1       moko      167: 
                    168:        error("get", fm, rc);
                    169:        return 0; // calm down compiler
                    170: }
                    171: 
1.2       moko      172: Value &VMemcached::mget(ArrayString& akeys) {
                    173:        VHash &hresult = *new VHash();
                    174:        
                    175:        size_t kl = akeys.count();
                    176:        
                    177:        if(kl==0)
                    178:                return hresult;
                    179:        
                    180:        const char **keys = new const char *[kl];
1.3       moko      181:        size_t *key_lengths = new size_t[kl];
1.2       moko      182:        
1.6       moko      183:        for(size_t i=0; i<kl; i++){
                    184:                const String &skey = *(akeys[i]);
                    185:                check_key(skey);
                    186:                keys[i] = skey.cstr();
                    187:                key_lengths[i] = skey.length();
1.2       moko      188:        }
                    189:        
1.3       moko      190:        check("mget", fm, f_memcached_mget(fm, keys, key_lengths, kl));
1.2       moko      191:        
1.7       moko      192:        // memcached_fetch_result calls memcached_result_create and memcached_result_free, we don't need to do this.
                    193:        memcached_result_st *results=0;
1.4       moko      194:        memcached_return rc;
                    195:        
1.7       moko      196:        while((results=f_memcached_fetch_result(fm, results, &rc)) && (rc == MEMCACHED_SUCCESS)){
1.4       moko      197:                const char *hkey = pa_strdup(f_memcached_result_key_value(results), f_memcached_result_key_length(results));
1.8       moko      198:                Serialization_data data(f_memcached_result_flags(results), f_memcached_result_value(results), f_memcached_result_length(results));
1.5       moko      199: 
1.8       moko      200:                hresult.hash().put(hkey, &deserialize(data));
1.2       moko      201:        }
1.4       moko      202: 
                    203:        if (rc != MEMCACHED_END && rc != MEMCACHED_NOTFOUND)
                    204:                error("mget", fm, rc);
1.2       moko      205:        
1.3       moko      206:        delete keys;
                    207:        delete key_lengths;
                    208:        
1.2       moko      209:        return hresult;
                    210: }
1.1       moko      211: 
1.11    ! moko      212: static inline time_t serialize_value(time_t ttl, const String& aname, Value* avalue, Serialization_data &data){
1.1       moko      213: 
                    214:        if(HashStringValue* hash=avalue->get_hash()) {
1.11    ! moko      215:                int valid_options=1;
        !           216:                if(Value* ttl_value=hash->get(expires_name)){
1.1       moko      217:                        ttl=ttl_value->as_int();
1.11    ! moko      218:                        valid_options++;
        !           219:                }
        !           220:                if(avalue=hash->get(value_name)){
        !           221:                        if(avalue->get_junction())
1.1       moko      222:                                throw Exception("memcached", 0, VALUE_NAME " must not be code");
                    223:                } else
1.2       moko      224:                        throw Exception("memcached", &aname, "value hash must contain ." VALUE_NAME);
1.11    ! moko      225:                        
        !           226:                if(valid_options!=hash->count())
        !           227:                        throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
1.1       moko      228:        }
                    229: 
1.8       moko      230:        if(avalue->is_string()){
                    231:                serialize_string(*avalue->get_string(), data);
                    232:        } else {
                    233:                throw Exception("memcached", &aname, "%s serialization not supported yet", avalue->type());
                    234:        }
1.1       moko      235: 
1.11    ! moko      236:        return ttl;
        !           237: }
        !           238: 
        !           239: bool VMemcached::add(const String& aname, Value* avalue){
        !           240:        check_key(aname);
        !           241: 
        !           242:        Serialization_data data;
        !           243:        time_t ttl=serialize_value(fttl, aname, avalue, data);
        !           244: 
        !           245:        memcached_return rc=f_memcached_add(fm, aname.cstr(), aname.length(), data.ptr, data.length, ttl, data.flags);
        !           246: 
        !           247:        if(rc == MEMCACHED_NOTSTORED)
        !           248:                return false;
        !           249: 
        !           250:        if(rc != MEMCACHED_SUCCESS)
        !           251:                error("add", fm, rc);
        !           252: 
        !           253:        return true;
        !           254: }
        !           255: 
        !           256: const VJunction* VMemcached::put_element(const String& aname, Value* avalue, bool /*replace*/){
        !           257:        check_key(aname);
        !           258: 
        !           259:        Serialization_data data;
        !           260:        time_t ttl=serialize_value(fttl, aname, avalue, data);
        !           261: 
        !           262:        check("set", fm, f_memcached_set(fm, aname.cstr(), aname.length(), data.ptr, data.length, ttl, data.flags));
1.1       moko      263: 
                    264:        return PUT_ELEMENT_REPLACED_ELEMENT;
                    265: }
                    266: 

E-mail: