Cache-Memcached-Fast

 view release on metacpan or  search on metacpan

Fast.xs  view on Meta::CPAN

    PROTOTYPE: $
    CODE:
        client_destroy(memd->c);
        if (memd->compress_method)
          {
            SvREFCNT_dec(memd->compress_method);
            SvREFCNT_dec(memd->decompress_method);
          }
        if (memd->serialize_method)
          {
            SvREFCNT_dec(memd->serialize_method);
            SvREFCNT_dec(memd->deserialize_method);
          }
        SvREFCNT_dec(memd->servers);
        Safefree(memd);


void
_weaken(sv)
        SV *sv
    PROTOTYPE: $
    CODE:
        sv_rvweaken(sv);


void
enable_compress(memd, enable)
        Cache_Memcached_Fast *  memd
        bool                    enable
    PROTOTYPE: $$
    CODE:
        if (enable && ! memd->compress_method)
          warn("Compression module was not found, can't enable compression");
        else if ((memd->compress_threshold > 0) != enable)
          memd->compress_threshold = -memd->compress_threshold;


void
set(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        add      =  CMD_ADD
        replace  =  CMD_REPLACE
        append   =  CMD_APPEND
        prepend  =  CMD_PREPEND
        cas      =  CMD_CAS
    PROTOTYPE: $@
    PREINIT:
        int noreply;
        struct result_object object =
            { NULL, result_store, NULL, NULL };
        const char *key;
        STRLEN key_len;
        cas_type cas = 0;
        const void *buf;
        STRLEN buf_len;
        flags_type flags = 0;
        exptime_type exptime = 0;
        int arg = 1;
        SV *sv;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        key = SvPV_stable_storage(aTHX_ ST(arg), &key_len);
        ++arg;
        if (ix == CMD_CAS)
          {
            cas = SvUV(ST(arg));
            ++arg;
          }
        sv = ST(arg);
        ++arg;
        sv = serialize(aTHX_ memd, sv, &flags);
        sv = compress(aTHX_ memd, sv, &flags);
        buf = (void *) SvPV_stable_storage(aTHX_ sv, &buf_len);
        if (buf_len > memd->max_size)
          XSRETURN_EMPTY;
        if (items > arg)
          {
            /* exptime doesn't have to be defined.  */
            sv = ST(arg);
            SvGETMAGIC(sv);
            if (SvOK(sv))
              exptime = SvIV(sv);
          }
        if (ix != CMD_CAS)
          {
            client_prepare_set(memd->c, ix, 0, key, key_len, flags,
                               exptime, buf, buf_len);
          }
        else
          {
            client_prepare_cas(memd->c, 0, key, key_len, cas, flags,
                               exptime, buf, buf_len);
          }
        client_execute(memd->c, 2);
        if (! noreply)
          {
            SV **val = av_fetch(object.arg, 0, 0);
            if (val)
              {
                PUSHs(*val);
                XSRETURN(1);
              }
            XSRETURN_EMPTY;
          }


void
set_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        add_multi      =  CMD_ADD
        replace_multi  =  CMD_REPLACE
        append_multi   =  CMD_APPEND
        prepend_multi  =  CMD_PREPEND
        cas_multi      =  CMD_CAS
    PROTOTYPE: $@
    PREINIT:
        int i, noreply;
        struct result_object object =
            { NULL, result_store, NULL, NULL };
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        for (i = 1; i < items; ++i)
          {
            SV *sv;
            AV *av;
            const char *key;
            STRLEN key_len;
            /*
              gcc-3.4.2 gives a warning about possibly uninitialized
              cas, so we set it to zero.
            */
            cas_type cas = 0;
            const void *buf;
            STRLEN buf_len;
            flags_type flags = 0;
            exptime_type exptime = 0;
            int arg = 0;

            sv = ST(i);
            if (! (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV))
              croak("Not an array reference");

            av = (AV *) SvRV(sv);
            key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, arg, 0), &key_len);
            ++arg;
            if (ix == CMD_CAS)
              {
                cas = SvUV(*safe_av_fetch(aTHX_ av, arg, 0));
                ++arg;
              }
            sv = *safe_av_fetch(aTHX_ av, arg, 0);
            ++arg;
            sv = serialize(aTHX_ memd, sv, &flags);
            sv = compress(aTHX_ memd, sv, &flags);
            buf = (void *) SvPV_stable_storage(aTHX_ sv, &buf_len);
            if (buf_len > memd->max_size)
              continue;
            if (av_len(av) >= arg)
              {
                /* exptime doesn't have to be defined.  */
                SV **ps = av_fetch(av, arg, 0);
                if (ps)
                  SvGETMAGIC(*ps);
                if (ps && SvOK(*ps))
                  exptime = SvIV(*ps);
              }

            if (ix != CMD_CAS)
              {
                client_prepare_set(memd->c, ix, i - 1, key, key_len, flags,
                                   exptime, buf, buf_len);
              }
            else
              {
                client_prepare_cas(memd->c, i - 1, key, key_len, cas, flags,
                                   exptime, buf, buf_len);
              }
          }
        client_execute(memd->c, 2);
        if (! noreply)
          {
            if (GIMME_V == G_SCALAR)
              {
                HV *hv = newHV();
                for (i = 0; i <= av_len(object.arg); ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val && SvOK(*val))
                      {
                        SV *key = *av_fetch((AV *) SvRV(ST(i + 1)), 0, 0);
                        HE *he = hv_store_ent(hv, key,
                                              SvREFCNT_inc(*val), 0);
                        if (! he)
                          SvREFCNT_dec(*val);
                      }
                  }
                mPUSHs(newRV_noinc((SV *) hv));
                XSRETURN(1);
              }
            else
              {
                I32 max_index = av_len(object.arg);
                EXTEND(SP, max_index + 1);
                for (i = 0; i <= max_index; ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val)
                      PUSHs(*val);
                    else
                      PUSHs(&PL_sv_undef);
                  }
                XSRETURN(max_index + 1);
              }
          }


void
get(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        gets        =  CMD_GETS
    PROTOTYPE: $@
    PREINIT:
        struct xs_value_result value_res;
        struct result_object object =
            { alloc_value, svalue_store, free_value, &value_res };
        const char *key;
        STRLEN key_len;
    PPCODE:
        value_res.memd = memd;
        value_res.vals = NULL;
        client_reset(memd->c, &object, 0);
        key = SvPV(ST(1), key_len);
        client_prepare_get(memd->c, ix, 0, key, key_len);
        client_execute(memd->c, 2);
        if (value_res.vals)
          {
            mPUSHs(value_res.vals);
            XSRETURN(1);
          }
        XSRETURN_EMPTY;


void
get_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        gets_multi  =  CMD_GETS
    PROTOTYPE: $@
    PREINIT:
        struct xs_value_result value_res;
        struct result_object object =
            { alloc_value, mvalue_store, free_value, &value_res };
        int i, key_count;
        HV *hv;
    PPCODE:
        key_count = items - 1;
        value_res.memd = memd;
        value_res.vals = (SV *) newAV();
        sv_2mortal(value_res.vals);
        av_extend((AV *) value_res.vals, key_count - 1);
        client_reset(memd->c, &object, 0);
        for (i = 0; i < key_count; ++i)
          {
            const char *key;
            STRLEN key_len;

            key = SvPV_stable_storage(aTHX_ ST(i + 1), &key_len);
            client_prepare_get(memd->c, ix, i, key, key_len);
          }
        client_execute(memd->c, 2);
        hv = newHV();
        for (i = 0; i <= av_len((AV *) value_res.vals); ++i)
          {
            SV **val = av_fetch((AV *) value_res.vals, i, 0);
            if (val && SvOK(*val))
              {
                SV *key = ST(i + 1);
                HE *he = hv_store_ent(hv, key,
                                      SvREFCNT_inc(*val), 0);
                if (! he)
                  SvREFCNT_dec(*val);
              }
          }
        mPUSHs(newRV_noinc((SV *) hv));
        XSRETURN(1);


void
gat(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        gats = CMD_GATS
    PROTOTYPE: $@
    PREINIT:
        struct xs_value_result value_res;
        struct result_object object =
            { alloc_value, svalue_store, free_value, &value_res };
        const char *key;
        STRLEN key_len;
        const char *exptime = "0";
        STRLEN exptime_len = 1;
        SV *sv;
    PPCODE:
        value_res.memd = memd;
        value_res.vals = NULL;
        client_reset(memd->c, &object, 0);
        sv = ST(1);
        SvGETMAGIC(sv);
        if (SvOK(sv))
          exptime = SvPV(sv, exptime_len);
        key = SvPV(ST(2), key_len);
        client_prepare_gat(memd->c, ix, 0, key, key_len, exptime, exptime_len);
        client_execute(memd->c, 4);
        if (value_res.vals)
          {
            mPUSHs(value_res.vals);
            XSRETURN(1);
          }
        XSRETURN_EMPTY;

void
gat_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        gats_multi = CMD_GATS
    PROTOTYPE: $@
    PREINIT:
        struct xs_value_result value_res;
        struct result_object object =
            { alloc_value, mvalue_store, free_value, &value_res };
        int i, key_count;
        HV *hv;
        SV *sv;
        const char *exptime = "0";
        STRLEN exptime_len = 1;
    PPCODE:
        key_count = items - 2;
        value_res.memd = memd;
        value_res.vals = (SV *) newAV();
        sv_2mortal(value_res.vals);
        if (key_count > 1)
          av_extend((AV *) value_res.vals, key_count - 1);
        client_reset(memd->c, &object, 0);
        sv = ST(1);
        SvGETMAGIC(sv);
        if (SvOK(sv))
          exptime = SvPV(sv, exptime_len);
        for (i = 0; i < key_count; ++i)
          {
            const char *key;
            STRLEN key_len;
            key = SvPV_stable_storage(aTHX_ ST(i + 2), &key_len);
            client_prepare_gat(memd->c, ix, i, key, key_len, exptime, exptime_len);
          }
        client_execute(memd->c, 4);
        hv = newHV();
        for (i = 0; i <= av_len((AV *) value_res.vals); ++i)
          {
            SV **val = av_fetch((AV *) value_res.vals, i, 0);
            if (val && SvOK(*val))
              {
                SV *key = ST(i + 2);
                HE *he = hv_store_ent(hv, key,
                                      SvREFCNT_inc(*val), 0);
                if (! he)
                  SvREFCNT_dec(*val);
              }
          }
        mPUSHs(newRV_noinc((SV *) hv));
        XSRETURN(1);


void
incr(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        decr  =  CMD_DECR
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { alloc_value, embedded_store, NULL, NULL };
        int noreply;
        const char *key;
        STRLEN key_len;
        arith_type arg = 1;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
        if (items > 2)
          {
            /* increment doesn't have to be defined.  */
            SV *sv = ST(2);
            SvGETMAGIC(sv);
            if (SvOK(sv))
              arg = SvUV(sv);
          }
        client_prepare_incr(memd->c, ix, 0, key, key_len, arg);
        client_execute(memd->c, 2);
        if (! noreply)
          {
            SV **val = av_fetch(object.arg, 0, 0);
            if (val)
              {
                PUSHs(*val);
                XSRETURN(1);
              }
            XSRETURN_EMPTY;
          }


void
incr_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        decr_multi  =  CMD_DECR
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { alloc_value, embedded_store, NULL, NULL };
        int i, noreply;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        for (i = 1; i < items; ++i)
          {
            SV *sv;
            AV *av;
            const char *key;
            STRLEN key_len;
            arith_type arg = 1;

            sv = ST(i);
            if (! SvROK(sv))
              {
                key = SvPV_stable_storage(aTHX_ sv, &key_len);
              }
            else
              {
                if (SvTYPE(SvRV(sv)) != SVt_PVAV)
                  croak("Not an array reference");

                av = (AV *) SvRV(sv);
                key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
                if (av_len(av) >= 1)
                  {
                    /* increment doesn't have to be defined.  */
                    SV **ps = av_fetch(av, 1, 0);
                    if (ps)
                      SvGETMAGIC(*ps);
                    if (ps && SvOK(*ps))
                      arg = SvUV(*ps);
                  }
              }
 
            client_prepare_incr(memd->c, ix, i - 1, key, key_len, arg);
          }
        client_execute(memd->c, 2);
        if (! noreply)
          {
            if (GIMME_V == G_SCALAR)
              {
                HV *hv = newHV();
                for (i = 0; i <= av_len(object.arg); ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val && SvOK(*val))
                      {
                        SV *key;
                        HE *he;

                        key = ST(i + 1);
                        if (SvROK(key))
                          key = *av_fetch((AV *) SvRV(key), 0, 0);

                        he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
                        if (! he)
                          SvREFCNT_dec(*val);
                      }
                  }
                mPUSHs(newRV_noinc((SV *) hv));
                XSRETURN(1);
              }
            else
              {
                I32 max_index = av_len(object.arg);
                EXTEND(SP, max_index + 1);
                for (i = 0; i <= max_index; ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val)
                      PUSHs(*val);
                    else
                      PUSHs(&PL_sv_undef);
                  }
                XSRETURN(max_index + 1);
              }
          }


void
delete(memd, ...)
        Cache_Memcached_Fast *  memd
    ALIAS:
        remove = CMD_REMOVE
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { NULL, result_store, NULL, NULL };
        int noreply;
        const char *key;
        STRLEN key_len;
    PPCODE:
        PERL_UNUSED_ARG(ix);
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
        if (items > 2)
          {
            /* Compatibility with old (key, delay) syntax.  */

            /* delay doesn't have to be defined.  */
            SV *sv = ST(2);
            SvGETMAGIC(sv);
            if (SvOK(sv) && SvUV(sv) != 0)
              warn("non-zero delete expiration time is ignored");
          }
        client_prepare_delete(memd->c, 0, key, key_len);
        client_execute(memd->c, 2);
        if (! noreply)
          {
            SV **val = av_fetch(object.arg, 0, 0);
            if (val)
              {
                PUSHs(*val);
                XSRETURN(1);
              }
            XSRETURN_EMPTY;
          }


void
delete_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { NULL, result_store, NULL, NULL };
        int i, noreply;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        for (i = 1; i < items; ++i)
          {
            SV *sv;
            const char *key;
            STRLEN key_len;

            sv = ST(i);
            if (! SvROK(sv))
              {
                key = SvPV_stable_storage(aTHX_ sv, &key_len);
              }
            else
              {
                /* Compatibility with old [key, delay] syntax.  */

                AV *av;

                if (SvTYPE(SvRV(sv)) != SVt_PVAV)
                  croak("Not an array reference");

                av = (AV *) SvRV(sv);
                key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, 0, 0), &key_len);
                if (av_len(av) >= 1)
                  {
                    /* delay doesn't have to be defined.  */
                    SV **ps = av_fetch(av, 1, 0);
                    if (ps)
                      SvGETMAGIC(*ps);
                    if (ps && SvOK(*ps) && SvUV(*ps) != 0)
                      warn("non-zero delete expiration time is ignored");
                  }
              }
 
            client_prepare_delete(memd->c, i - 1, key, key_len);
          }
        client_execute(memd->c, 2);
        if (! noreply)
          {
            if (GIMME_V == G_SCALAR)
              {
                HV *hv = newHV();
                for (i = 0; i <= av_len(object.arg); ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val && SvOK(*val))
                      {
                        SV *key;
                        HE *he;

                        key = ST(i + 1);
                        if (SvROK(key))
                          key = *av_fetch((AV *) SvRV(key), 0, 0);

                        he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
                        if (! he)
                          SvREFCNT_dec(*val);
                      }
                  }
                mPUSHs(newRV_noinc((SV *) hv));
                XSRETURN(1);
              }
            else
              {
                I32 max_index = av_len(object.arg);
                EXTEND(SP, max_index + 1);
                for (i = 0; i <= max_index; ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val)
                      PUSHs(*val);
                    else
                      PUSHs(&PL_sv_undef);
                  }
                XSRETURN(max_index + 1);
              }
          }


void
touch(memd, ...)
        Cache_Memcached_Fast *  memd
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { NULL, result_store, NULL, NULL };
        int noreply;
        const char *key;
        STRLEN key_len;
        exptime_type exptime = 0;
        SV *sv;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        key = SvPV_stable_storage(aTHX_ ST(1), &key_len);
        if (items > 2)
          {
            /* exptime doesn't have to be defined.  */
            sv = ST(2);
            SvGETMAGIC(sv);
            if (SvOK(sv))
              exptime = SvIV(sv);
          }
        client_prepare_touch(memd->c, 0, key, key_len, exptime);
        client_execute(memd->c, 2);
        if (! noreply)
          {
            SV **val = av_fetch(object.arg, 0, 0);
            if (val)
              {
                PUSHs(*val);
                XSRETURN(1);
              }
            XSRETURN_EMPTY;
          }


void
touch_multi(memd, ...)
        Cache_Memcached_Fast *  memd
    PROTOTYPE: $@
    PREINIT:
        struct result_object object =
            { NULL, result_store, NULL, NULL };
        int i, noreply;
    PPCODE:
        object.arg = newAV();
        sv_2mortal((SV *) object.arg);
        noreply = (GIMME_V == G_VOID);
        client_reset(memd->c, &object, noreply);
        for (i = 1; i < items; ++i)
          {
            SV *sv;
            AV *av;
            const char *key;
            STRLEN key_len;
            exptime_type exptime = 0;
            int arg = 0;

            sv = ST(i);
            if (! (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV))
              croak("Not an array reference");

            av = (AV *) SvRV(sv);
            key = SvPV_stable_storage(aTHX_ *safe_av_fetch(aTHX_ av, arg, 0), &key_len);
            ++arg;

            if (av_len(av) >= 1)
              {
                /* exptime doesn't have to be defined.  */
                SV **ps = av_fetch(av, arg, 0);
                if (ps)
                  SvGETMAGIC(*ps);
                if (ps && SvOK(*ps))
                  exptime = SvIV(*ps);
              }

            client_prepare_touch(memd->c, i - 1, key, key_len, exptime);
          }
        client_execute(memd->c, 2);
        if (! noreply)
          {
            if (GIMME_V == G_SCALAR)
              {
                HV *hv = newHV();
                for (i = 0; i <= av_len(object.arg); ++i)
                  {
                    SV **val = av_fetch(object.arg, i, 0);
                    if (val && SvOK(*val))
                      {
                        SV *key;
                        HE *he;

                        key = ST(i + 1);
                        if (SvROK(key))
                          key = *av_fetch((AV *) SvRV(key), 0, 0);

                        he = hv_store_ent(hv, key, SvREFCNT_inc(*val), 0);
                        if (! he)
                          SvREFCNT_dec(*val);
                      }
                  }
                mPUSHs(newRV_noinc((SV *) hv));
                XSRETURN(1);
              }
            else



( run in 1.834 second using v1.01-cache-2.11-cpan-71847e10f99 )