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: