支持Head获取对象元信息操作,支持从redis获取元信息;调整内部超时检查逻辑;
This commit is contained in:
1
cache/include/cache_evbase_client.h
vendored
1
cache/include/cache_evbase_client.h
vendored
@@ -34,6 +34,7 @@ struct cache_evbase_instance *cache_evbase_instance_new(const char* profile_path
|
||||
|
||||
//GET<45>ӿڣ<D3BF><DAA3>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><30>ʧ<EFBFBD>ܷ<EFBFBD><DCB7><EFBFBD>-1<><31>future<72>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD><DFB3><EFBFBD>ִ<EFBFBD>У<EFBFBD><D0A3><EFBFBD>ͬ
|
||||
int cache_evbase_fetch_object(struct cache_evbase_instance *instance, struct future* f, struct tango_cache_meta_get *meta);
|
||||
int cache_evbase_head_object(struct cache_evbase_instance *instance, struct future* f, struct tango_cache_meta_get *meta);
|
||||
struct tango_cache_result *cache_evbase_read_result(void *promise_result);
|
||||
|
||||
//DELETE<54>ӿ<EFBFBD>
|
||||
|
||||
5
cache/include/tango_cache_client.h
vendored
5
cache/include/tango_cache_client.h
vendored
@@ -19,6 +19,8 @@ enum CACHE_ERR_CODE
|
||||
CACHE_ERR_WIREDLB,
|
||||
CACHE_ERR_SOCKPAIR,
|
||||
CACHE_ERR_INTERNAL,
|
||||
CACHE_ERR_REDIS_JSON,
|
||||
CACHE_ERR_REDIS_CONNECT,
|
||||
};
|
||||
|
||||
enum PUT_MEMORY_COPY_WAY
|
||||
@@ -79,7 +81,7 @@ enum CACHE_HTTP_HDR_TYPE
|
||||
|
||||
struct tango_cache_meta_get
|
||||
{
|
||||
const char* url; //<2F><><EFBFBD><EFBFBD>:URL<EFBFBD><EFBFBD><EFBFBD>ǽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>־:<3A>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CACHE_OBJECT_KEY_HASH_SWITCH=0ʱ<30><CAB1><EFBFBD><EFBFBD>256<35>ֽڣ<D6BD>=1ʱ<31><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
const char* url; //<2F><><EFBFBD><EFBFBD>:URI<EFBFBD><EFBFBD><EFBFBD>ǽṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>־:<3A>ļ<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD>'/'<27><>ͷ<EFBFBD><EFBFBD>CACHE_OBJECT_KEY_HASH_SWITCH=0ʱ<30><CAB1><EFBFBD><EFBFBD>256<35>ֽڣ<D6BD>=1ʱ<31><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
struct request_freshness get;
|
||||
};
|
||||
|
||||
@@ -112,6 +114,7 @@ struct tango_cache_instance *tango_cache_instance_new(struct event_base* evbase,
|
||||
//ʧ<><CAA7>ʱ<EFBFBD>ص<EFBFBD>promise_failed(<28><>һ<EFBFBD><D2BB>)<29><>ʹ<EFBFBD><CAB9>get_last_error<6F><72>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>룻
|
||||
//future<72><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΪNULL
|
||||
int tango_cache_fetch_object(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta);
|
||||
int tango_cache_head_object(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta);
|
||||
//<2F><>promise_success<73><73>result<6C><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
|
||||
struct tango_cache_result *tango_cache_read_result(future_result_t *promise_result);
|
||||
|
||||
|
||||
2
cache/src/README.txt
vendored
Normal file
2
cache/src/README.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
HEAD<EFBFBD><EFBFBD><EFBFBD><EFBFBD>֧<EFBFBD>ִ<EFBFBD>minio<EFBFBD><EFBFBD>redis<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>Ĭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD>minio<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>redis<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>Ӻ궨<EFBFBD><EFBFBD>-DHEAD_OBJECT_FROM_REDIS
|
||||
596
cache/src/cJSON/cJSON.c
vendored
Normal file
596
cache/src/cJSON/cJSON.c
vendored
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* cJSON */
|
||||
/* JSON parser in C. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include "cJSON.h"
|
||||
|
||||
static const char *ep;
|
||||
|
||||
const char *cJSON_GetErrorPtr(void) {return ep;}
|
||||
|
||||
static int cJSON_strcasecmp(const char *s1,const char *s2)
|
||||
{
|
||||
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
|
||||
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
|
||||
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
|
||||
}
|
||||
|
||||
static void *(*cJSON_malloc)(size_t sz) = malloc;
|
||||
static void (*cJSON_free)(void *ptr) = free;
|
||||
|
||||
static char* cJSON_strdup(const char* str)
|
||||
{
|
||||
size_t len;
|
||||
char* copy;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
if (!(copy = (char*)cJSON_malloc(len))) return 0;
|
||||
memcpy(copy,str,len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks)
|
||||
{
|
||||
if (!hooks) { /* Reset hooks */
|
||||
cJSON_malloc = malloc;
|
||||
cJSON_free = free;
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
|
||||
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
|
||||
}
|
||||
|
||||
/* Internal constructor. */
|
||||
static cJSON *cJSON_New_Item(void)
|
||||
{
|
||||
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
|
||||
if (node) memset(node,0,sizeof(cJSON));
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Delete a cJSON structure. */
|
||||
void cJSON_Delete(cJSON *c)
|
||||
{
|
||||
cJSON *next;
|
||||
while (c)
|
||||
{
|
||||
next=c->next;
|
||||
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
|
||||
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
|
||||
if (c->string) cJSON_free(c->string);
|
||||
cJSON_free(c);
|
||||
c=next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the input text to generate a number, and populate the result into item. */
|
||||
static const char *parse_number(cJSON *item,const char *num)
|
||||
{
|
||||
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
|
||||
|
||||
if (*num=='-') sign=-1,num++; /* Has sign? */
|
||||
if (*num=='0') num++; /* is zero */
|
||||
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
|
||||
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
|
||||
if (*num=='e' || *num=='E') /* Exponent? */
|
||||
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
|
||||
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
|
||||
}
|
||||
|
||||
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
|
||||
|
||||
item->valuedouble=n;
|
||||
item->valueint=(int)n;
|
||||
item->type=cJSON_Number;
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Render the number nicely from the given item into a string. */
|
||||
static char *print_number(cJSON *item)
|
||||
{
|
||||
char *str;
|
||||
double d=item->valuedouble;
|
||||
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
|
||||
{
|
||||
str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
|
||||
if (str) sprintf(str,"%d",item->valueint);
|
||||
}
|
||||
else
|
||||
{
|
||||
str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
|
||||
if (str)
|
||||
{
|
||||
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
|
||||
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
|
||||
else sprintf(str,"%f",d);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static unsigned parse_hex4(const char *str)
|
||||
{
|
||||
unsigned h=0;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
h=h<<4;str++;
|
||||
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
{
|
||||
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
|
||||
if (*str!='\"') {ep=str;return 0;} /* not a string! */
|
||||
|
||||
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||
|
||||
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
|
||||
if (!out) return 0;
|
||||
|
||||
ptr=str+1;ptr2=out;
|
||||
while (*ptr!='\"' && *ptr)
|
||||
{
|
||||
if (*ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
switch (*ptr)
|
||||
{
|
||||
case 'b': *ptr2++='\b'; break;
|
||||
case 'f': *ptr2++='\f'; break;
|
||||
case 'n': *ptr2++='\n'; break;
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
|
||||
|
||||
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
|
||||
uc2=parse_hex4(ptr+3);ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
|
||||
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
|
||||
}
|
||||
|
||||
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
|
||||
|
||||
switch (len) {
|
||||
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
|
||||
case 1: *--ptr2 =(uc | firstByteMark[len]);
|
||||
}
|
||||
ptr2+=len;
|
||||
break;
|
||||
default: *ptr2++=*ptr; break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
*ptr2=0;
|
||||
if (*ptr=='\"') ptr++;
|
||||
item->valuestring=out;
|
||||
item->type=cJSON_String;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Render the cstring provided to an escaped version that can be printed. */
|
||||
static char *print_string_ptr(const char *str)
|
||||
{
|
||||
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
|
||||
|
||||
if (!str) return cJSON_strdup("");
|
||||
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
|
||||
|
||||
out=(char*)cJSON_malloc(len+3);
|
||||
if (!out) return 0;
|
||||
|
||||
ptr2=out;ptr=str;
|
||||
*ptr2++='\"';
|
||||
while (*ptr)
|
||||
{
|
||||
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
|
||||
else
|
||||
{
|
||||
*ptr2++='\\';
|
||||
switch (token=*ptr++)
|
||||
{
|
||||
case '\\': *ptr2++='\\'; break;
|
||||
case '\"': *ptr2++='\"'; break;
|
||||
case '\b': *ptr2++='b'; break;
|
||||
case '\f': *ptr2++='f'; break;
|
||||
case '\n': *ptr2++='n'; break;
|
||||
case '\r': *ptr2++='r'; break;
|
||||
case '\t': *ptr2++='t'; break;
|
||||
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
|
||||
}
|
||||
}
|
||||
}
|
||||
*ptr2++='\"';*ptr2++=0;
|
||||
return out;
|
||||
}
|
||||
/* Invote print_string_ptr (which is useful) on an item. */
|
||||
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
|
||||
|
||||
/* Predeclare these prototypes. */
|
||||
static const char *parse_value(cJSON *item,const char *value);
|
||||
static char *print_value(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_array(cJSON *item,const char *value);
|
||||
static char *print_array(cJSON *item,int depth,int fmt);
|
||||
static const char *parse_object(cJSON *item,const char *value);
|
||||
static char *print_object(cJSON *item,int depth,int fmt);
|
||||
|
||||
/* Utility to jump whitespace and cr/lf */
|
||||
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
|
||||
|
||||
/* Parse an object - create a new root, and populate. */
|
||||
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
|
||||
{
|
||||
const char *end=0;
|
||||
cJSON *c=cJSON_New_Item();
|
||||
ep=0;
|
||||
if (!c) return 0; /* memory fail */
|
||||
|
||||
end=parse_value(c,skip(value));
|
||||
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
|
||||
|
||||
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
|
||||
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
|
||||
if (return_parse_end) *return_parse_end=end;
|
||||
return c;
|
||||
}
|
||||
/* Default options for cJSON_Parse */
|
||||
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
|
||||
|
||||
/* Render a cJSON item/entity/structure to text. */
|
||||
char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
|
||||
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
|
||||
|
||||
/* Parser core - when encountering text, process appropriately. */
|
||||
static const char *parse_value(cJSON *item,const char *value)
|
||||
{
|
||||
if (!value) return 0; /* Fail on null. */
|
||||
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
|
||||
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
|
||||
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
|
||||
if (*value=='\"') { return parse_string(item,value); }
|
||||
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
|
||||
if (*value=='[') { return parse_array(item,value); }
|
||||
if (*value=='{') { return parse_object(item,value); }
|
||||
|
||||
ep=value;return 0; /* failure. */
|
||||
}
|
||||
|
||||
/* Render a value to text. */
|
||||
static char *print_value(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char *out=0;
|
||||
if (!item) return 0;
|
||||
switch ((item->type)&255)
|
||||
{
|
||||
case cJSON_NULL: out=cJSON_strdup("null"); break;
|
||||
case cJSON_False: out=cJSON_strdup("false");break;
|
||||
case cJSON_True: out=cJSON_strdup("true"); break;
|
||||
case cJSON_Number: out=print_number(item);break;
|
||||
case cJSON_String: out=print_string(item);break;
|
||||
case cJSON_Array: out=print_array(item,depth,fmt);break;
|
||||
case cJSON_Object: out=print_object(item,depth,fmt);break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an array from input text. */
|
||||
static const char *parse_array(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='[') {ep=value;return 0;} /* not an array! */
|
||||
|
||||
item->type=cJSON_Array;
|
||||
value=skip(value+1);
|
||||
if (*value==']') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0; /* memory fail */
|
||||
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_value(child,skip(value+1)));
|
||||
if (!value) return 0; /* memory fail */
|
||||
}
|
||||
|
||||
if (*value==']') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an array to text */
|
||||
static char *print_array(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries;
|
||||
char *out=0,*ptr,*ret;int len=5;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,i=0,fail=0;
|
||||
|
||||
/* How many entries in the array? */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle numentries==0 */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(3);
|
||||
if (out) strcpy(out,"[]");
|
||||
return out;
|
||||
}
|
||||
/* Allocate an array to hold the values for each */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
memset(entries,0,numentries*sizeof(char*));
|
||||
/* Retrieve all the results: */
|
||||
child=item->child;
|
||||
while (child && !fail)
|
||||
{
|
||||
ret=print_value(child,depth+1,fmt);
|
||||
entries[i++]=ret;
|
||||
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* If we didn't fail, try to malloc the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
/* If that fails, we fail. */
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure. */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
|
||||
cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output array. */
|
||||
*out='[';
|
||||
ptr=out+1;*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
|
||||
cJSON_free(entries[i]);
|
||||
}
|
||||
cJSON_free(entries);
|
||||
*ptr++=']';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Build an object from the text. */
|
||||
static const char *parse_object(cJSON *item,const char *value)
|
||||
{
|
||||
cJSON *child;
|
||||
if (*value!='{') {ep=value;return 0;} /* not an object! */
|
||||
|
||||
item->type=cJSON_Object;
|
||||
value=skip(value+1);
|
||||
if (*value=='}') return value+1; /* empty array. */
|
||||
|
||||
item->child=child=cJSON_New_Item();
|
||||
if (!item->child) return 0;
|
||||
value=skip(parse_string(child,skip(value)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
|
||||
while (*value==',')
|
||||
{
|
||||
cJSON *new_item;
|
||||
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
|
||||
child->next=new_item;new_item->prev=child;child=new_item;
|
||||
value=skip(parse_string(child,skip(value+1)));
|
||||
if (!value) return 0;
|
||||
child->string=child->valuestring;child->valuestring=0;
|
||||
if (*value!=':') {ep=value;return 0;} /* fail! */
|
||||
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
|
||||
if (!value) return 0;
|
||||
}
|
||||
|
||||
if (*value=='}') return value+1; /* end of array */
|
||||
ep=value;return 0; /* malformed. */
|
||||
}
|
||||
|
||||
/* Render an object to text. */
|
||||
static char *print_object(cJSON *item,int depth,int fmt)
|
||||
{
|
||||
char **entries=0,**names=0;
|
||||
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
|
||||
cJSON *child=item->child;
|
||||
int numentries=0,fail=0;
|
||||
/* Count the number of entries. */
|
||||
while (child) numentries++,child=child->next;
|
||||
/* Explicitly handle empty object case */
|
||||
if (!numentries)
|
||||
{
|
||||
out=(char*)cJSON_malloc(fmt?depth+4:3);
|
||||
if (!out) return 0;
|
||||
ptr=out;*ptr++='{';
|
||||
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
/* Allocate space for the names and the objects */
|
||||
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!entries) return 0;
|
||||
names=(char**)cJSON_malloc(numentries*sizeof(char*));
|
||||
if (!names) {cJSON_free(entries);return 0;}
|
||||
memset(entries,0,sizeof(char*)*numentries);
|
||||
memset(names,0,sizeof(char*)*numentries);
|
||||
|
||||
/* Collect all the results into our arrays: */
|
||||
child=item->child;depth++;if (fmt) len+=depth;
|
||||
while (child)
|
||||
{
|
||||
names[i]=str=print_string_ptr(child->string);
|
||||
entries[i++]=ret=print_value(child,depth,fmt);
|
||||
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
|
||||
child=child->next;
|
||||
}
|
||||
|
||||
/* Try to allocate the output string */
|
||||
if (!fail) out=(char*)cJSON_malloc(len);
|
||||
if (!out) fail=1;
|
||||
|
||||
/* Handle failure */
|
||||
if (fail)
|
||||
{
|
||||
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose the output: */
|
||||
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
|
||||
for (i=0;i<numentries;i++)
|
||||
{
|
||||
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
|
||||
strcpy(ptr,names[i]);ptr+=strlen(names[i]);
|
||||
*ptr++=':';if (fmt) *ptr++='\t';
|
||||
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
|
||||
if (i!=numentries-1) *ptr++=',';
|
||||
if (fmt) *ptr++='\n';*ptr=0;
|
||||
cJSON_free(names[i]);cJSON_free(entries[i]);
|
||||
}
|
||||
|
||||
cJSON_free(names);cJSON_free(entries);
|
||||
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
|
||||
*ptr++='}';*ptr++=0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Get Array size/item / object item. */
|
||||
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
|
||||
|
||||
/* Utility for array list handling. */
|
||||
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
|
||||
/* Utility for handling references. */
|
||||
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
|
||||
|
||||
/* Add item to array/object. */
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
|
||||
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
|
||||
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
|
||||
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
|
||||
|
||||
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
|
||||
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
|
||||
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
|
||||
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
|
||||
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
|
||||
|
||||
/* Replace array/object items with new ones. */
|
||||
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
|
||||
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
|
||||
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
|
||||
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
|
||||
|
||||
/* Create basic types: */
|
||||
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
|
||||
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
|
||||
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
|
||||
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
|
||||
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
|
||||
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
|
||||
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
|
||||
|
||||
/* Create Arrays: */
|
||||
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
|
||||
|
||||
/* Duplication */
|
||||
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
|
||||
{
|
||||
cJSON *newitem,*cptr,*nptr=0,*newchild;
|
||||
/* Bail on bad ptr */
|
||||
if (!item) return 0;
|
||||
/* Create new item */
|
||||
newitem=cJSON_New_Item();
|
||||
if (!newitem) return 0;
|
||||
/* Copy over all vars */
|
||||
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
|
||||
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
|
||||
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
|
||||
/* If non-recursive, then we're done! */
|
||||
if (!recurse) return newitem;
|
||||
/* Walk the ->next chain for the child. */
|
||||
cptr=item->child;
|
||||
while (cptr)
|
||||
{
|
||||
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
|
||||
if (!newchild) {cJSON_Delete(newitem);return 0;}
|
||||
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
|
||||
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
|
||||
cptr=cptr->next;
|
||||
}
|
||||
return newitem;
|
||||
}
|
||||
|
||||
void cJSON_Minify(char *json)
|
||||
{
|
||||
char *into=json;
|
||||
while (*json)
|
||||
{
|
||||
if (*json==' ') json++;
|
||||
else if (*json=='\t') json++; // Whitespace characters.
|
||||
else if (*json=='\r') json++;
|
||||
else if (*json=='\n') json++;
|
||||
else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line.
|
||||
else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments.
|
||||
else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
|
||||
else *into++=*json++; // All other characters.
|
||||
}
|
||||
*into=0; // and null-terminate.
|
||||
}
|
||||
143
cache/src/cJSON/cJSON.h
vendored
Normal file
143
cache/src/cJSON/cJSON.h
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
46
cache/src/cache_evbase_client.cpp
vendored
46
cache/src/cache_evbase_client.cpp
vendored
@@ -17,6 +17,9 @@
|
||||
#include "cache_evbase_client.h"
|
||||
#include "tango_cache_transfer.h"
|
||||
#include "tango_cache_tools.h"
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
#include "tango_cache_redis.h"
|
||||
#endif
|
||||
|
||||
enum CACHE_ASYN_CMD
|
||||
{
|
||||
@@ -28,6 +31,7 @@ enum CACHE_ASYN_CMD
|
||||
CACHE_ASYN_UPLOAD_FRAG_EVBUF,
|
||||
CACHE_ASYN_UPLOAD_END,
|
||||
CACHE_ASYN_DELETE,
|
||||
CACHE_ASYN_HEAD,
|
||||
};
|
||||
|
||||
struct databuffer
|
||||
@@ -158,7 +162,15 @@ static void cache_asyn_ioevent_dispatch(struct databuffer *buffer)
|
||||
tango_cache_fetch_start(ctx_asyn->ctx);
|
||||
cache_asyn_ctx_destroy(ctx_asyn);
|
||||
break;
|
||||
|
||||
case CACHE_ASYN_HEAD:
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
tango_cache_head_redis(ctx_asyn->ctx);
|
||||
#else
|
||||
tango_cache_fetch_start(ctx_asyn->ctx);
|
||||
#endif
|
||||
cache_asyn_ctx_destroy(ctx_asyn);
|
||||
break;
|
||||
|
||||
case CACHE_ASYN_DELETE:
|
||||
cache_delete_minio_object(ctx_asyn->ctx);
|
||||
cache_asyn_ctx_destroy(ctx_asyn);
|
||||
@@ -450,7 +462,7 @@ int cache_evbase_fetch_object(struct cache_evbase_instance *instance, struct fut
|
||||
|
||||
ctx_asyn = (struct cache_evbase_ctx *)calloc(1, sizeof(struct cache_evbase_ctx));
|
||||
ctx_asyn->instance_asyn = instance;
|
||||
ctx_asyn->ctx = tango_cache_fetch_prepare(instance->instance, f, meta);
|
||||
ctx_asyn->ctx = tango_cache_fetch_prepare(instance->instance, CACHE_REQUEST_GET, f, meta);
|
||||
if(ctx_asyn->ctx == NULL)
|
||||
{
|
||||
free(ctx_asyn);
|
||||
@@ -473,6 +485,36 @@ int cache_evbase_fetch_object(struct cache_evbase_instance *instance, struct fut
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cache_evbase_head_object(struct cache_evbase_instance *instance, struct future* f, struct tango_cache_meta_get *meta)
|
||||
{
|
||||
struct cache_evbase_ctx *ctx_asyn;
|
||||
struct databuffer *buffer;
|
||||
|
||||
ctx_asyn = (struct cache_evbase_ctx *)calloc(1, sizeof(struct cache_evbase_ctx));
|
||||
ctx_asyn->instance_asyn = instance;
|
||||
ctx_asyn->ctx = tango_cache_fetch_prepare(instance->instance, CACHE_REQUEST_HEAD, f, meta);
|
||||
if(ctx_asyn->ctx == NULL)
|
||||
{
|
||||
free(ctx_asyn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer = (struct databuffer *)malloc(sizeof(struct databuffer));
|
||||
buffer->ctx_asyn = ctx_asyn;
|
||||
buffer->cmd_type = CACHE_ASYN_HEAD;
|
||||
|
||||
if(iothread_notify_event(instance->notify_sendfd, &buffer, sizeof(void *), 2) != sizeof(void *))
|
||||
{
|
||||
tango_cache_set_fail_state(ctx_asyn->ctx, CACHE_ERR_SOCKPAIR);
|
||||
promise_failed(future_to_promise(f), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx_asyn->ctx));
|
||||
tango_cache_ctx_destroy(ctx_asyn->ctx);
|
||||
cache_asyn_ctx_destroy(ctx_asyn);
|
||||
free(buffer);
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cache_evbase_delete_object(struct cache_evbase_instance *instance, struct future* f, const char *objkey)
|
||||
{
|
||||
struct cache_evbase_ctx *ctx_asyn;
|
||||
|
||||
58
cache/src/tango_cache_client.cpp
vendored
58
cache/src/tango_cache_client.cpp
vendored
@@ -17,6 +17,9 @@
|
||||
#include "tango_cache_transfer.h"
|
||||
#include "tango_cache_tools.h"
|
||||
#include "tango_cache_xml.h"
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
#include "tango_cache_redis.h"
|
||||
#endif
|
||||
|
||||
int TANGO_CACHE_VERSION_20181009=0;
|
||||
|
||||
@@ -91,6 +94,8 @@ const char *tango_cache_get_errstring(const struct tango_cache_ctx *ctx)
|
||||
case CACHE_ERR_WIREDLB: return "wiredlb error";
|
||||
case CACHE_ERR_SOCKPAIR:return "socketpair error";
|
||||
case CACHE_ERR_INTERNAL:return "internal error";
|
||||
case CACHE_ERR_REDIS_JSON:return "parse redis json error";
|
||||
case CACHE_ERR_REDIS_CONNECT:return "redis is not connected";
|
||||
default: return ctx->error;
|
||||
}
|
||||
}
|
||||
@@ -137,6 +142,7 @@ static void update_statistics(struct tango_cache_ctx *ctx, struct cache_statisti
|
||||
}
|
||||
break;
|
||||
case CACHE_REQUEST_GET:
|
||||
case CACHE_REQUEST_HEAD:
|
||||
if(ctx->fail_state)
|
||||
{
|
||||
if(ctx->error_code == CACHE_CACHE_MISS || ctx->error_code == CACHE_TIMEOUT)
|
||||
@@ -204,6 +210,7 @@ void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx)
|
||||
switch(ctx->method)
|
||||
{
|
||||
case CACHE_REQUEST_GET:
|
||||
case CACHE_REQUEST_HEAD:
|
||||
easy_string_destroy(&ctx->get.response_tag);
|
||||
break;
|
||||
|
||||
@@ -431,7 +438,7 @@ int tango_cache_upload_once_evbuf(struct tango_cache_instance *instance, struct
|
||||
return tango_cache_upload_once_start_evbuf(ctx, way, evbuf);
|
||||
}
|
||||
|
||||
struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta)
|
||||
struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *instance, enum CACHE_REQUEST_METHOD method, struct future* f, struct tango_cache_meta_get *meta)
|
||||
{
|
||||
struct tango_cache_ctx *ctx;
|
||||
char sha256[72];
|
||||
@@ -439,7 +446,7 @@ struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *i
|
||||
ctx = (struct tango_cache_ctx *)calloc(1, sizeof(struct tango_cache_ctx));
|
||||
ctx->instance = instance;
|
||||
ctx->future = f;
|
||||
ctx->method = CACHE_REQUEST_GET;
|
||||
ctx->method = method;
|
||||
ctx->get.state = GET_STATE_START;
|
||||
ctx->get.max_age = meta->get.max_age;
|
||||
ctx->get.min_fresh = meta->get.min_fresh;
|
||||
@@ -467,7 +474,7 @@ int tango_cache_fetch_object(struct tango_cache_instance *instance, struct futur
|
||||
{
|
||||
struct tango_cache_ctx *ctx;
|
||||
|
||||
ctx = tango_cache_fetch_prepare(instance, f, meta);
|
||||
ctx = tango_cache_fetch_prepare(instance, CACHE_REQUEST_GET, f, meta);
|
||||
if(ctx == NULL)
|
||||
{
|
||||
return -1;
|
||||
@@ -475,6 +482,22 @@ int tango_cache_fetch_object(struct tango_cache_instance *instance, struct futur
|
||||
return tango_cache_fetch_start(ctx);
|
||||
}
|
||||
|
||||
int tango_cache_head_object(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta)
|
||||
{
|
||||
struct tango_cache_ctx *ctx;
|
||||
|
||||
ctx = tango_cache_fetch_prepare(instance, CACHE_REQUEST_HEAD, f, meta);
|
||||
if(ctx == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
return tango_cache_head_redis(ctx);
|
||||
#else
|
||||
return tango_cache_fetch_start(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct tango_cache_ctx *tango_cache_delete_prepare(struct tango_cache_instance *instance, struct future* f, const char *objkey)
|
||||
{
|
||||
struct tango_cache_ctx *ctx;
|
||||
@@ -585,6 +608,7 @@ static void check_multi_info(CURLM *multi)
|
||||
switch(ctx->method)
|
||||
{
|
||||
case CACHE_REQUEST_GET:
|
||||
case CACHE_REQUEST_HEAD:
|
||||
tango_cache_curl_get_done(ctx, res, res_code);
|
||||
break;
|
||||
case CACHE_REQUEST_PUT:
|
||||
@@ -732,7 +756,20 @@ static int load_local_configure(struct tango_cache_instance *instance, const cha
|
||||
MESA_load_profile_uint_def(profile_path, section, "MAX_USED_MEMORY_SIZE_MB", &intval, 5120);
|
||||
longval = intval;
|
||||
instance->cache_limit_size = longval * 1024 * 1024;
|
||||
MESA_load_profile_string_def(profile_path, section, "CACHE_BUCKET_NAME", instance->bucketname, 256, "openbucket");
|
||||
if(MESA_load_profile_string_nodef(profile_path, section, "CACHE_BUCKET_NAME", instance->bucketname, 256) < 0)
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_FATAL, "Load config %s [%s] CACHE_BUCKET_NAME not found.\n", profile_path, section);
|
||||
return -1;
|
||||
}
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
MESA_load_profile_string_def(profile_path, section, "CACHE_REDIS_KEY", instance->redis_key, 256, instance->bucketname);
|
||||
if(MESA_load_profile_string_nodef(profile_path, section, "CACHE_REDIS_IP", instance->redis_ip, 256) < 0)
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_FATAL, "Load config %s [%s] CACHE_REDIS_IP not found.\n", profile_path, section);
|
||||
return -1;
|
||||
}
|
||||
MESA_load_profile_int_def(profile_path, section, "CACHE_REDIS_PORT", &instance->redis_port, 6379);
|
||||
#endif
|
||||
MESA_load_profile_uint_def(profile_path, section, "CACHE_OBJECT_KEY_HASH_SWITCH", &instance->hash_object_key, 1);
|
||||
MESA_load_profile_uint_def(profile_path, section, "MINIO_LISTEN_PORT", &instance->minio_port, 9000);
|
||||
if(MESA_load_profile_string_nodef(profile_path, section, "MINIO_IP_LIST", instance->minio_iplist, 4096) < 0)
|
||||
@@ -792,8 +829,19 @@ struct tango_cache_instance *tango_cache_instance_new(struct event_base* evbase,
|
||||
curl_multi_setopt(instance->multi_hd, CURLMOPT_TIMERFUNCTION, curl_timer_function_cb);
|
||||
curl_multi_setopt(instance->multi_hd, CURLMOPT_TIMERDATA, instance);
|
||||
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
if(redis_asyn_connect_init(instance, instance->redis_ip, instance->redis_port))
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_FATAL, "redis_asyn_connect_init %s:%u failed.", instance->redis_ip, instance->redis_port);
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_FATAL, "redis_asyn_connect_init %s:%u success.", instance->redis_ip, instance->redis_port);
|
||||
}
|
||||
#endif
|
||||
evtimer_assign(&instance->timer_event, evbase, libevent_timer_event_cb, instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
13
cache/src/tango_cache_client_in.h
vendored
13
cache/src/tango_cache_client_in.h
vendored
@@ -6,6 +6,9 @@
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <event.h>
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
#include <hiredis/async.h>
|
||||
#endif
|
||||
|
||||
#include <MESA/wiredLB.h>
|
||||
#include "tango_cache_client.h"
|
||||
@@ -20,6 +23,7 @@ enum CACHE_REQUEST_METHOD
|
||||
CACHE_REQUEST_PUT,
|
||||
CACHE_REQUEST_DELETE,
|
||||
CACHE_REQUEST_DELETE_MUL,
|
||||
CACHE_REQUEST_HEAD,
|
||||
};
|
||||
|
||||
enum GET_OBJECT_STATE
|
||||
@@ -67,6 +71,13 @@ struct tango_cache_instance
|
||||
long max_cnn_host;
|
||||
u_int32_t upload_block_size; //minio<69>ֶ<EFBFBD><D6B6>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>
|
||||
enum CACHE_ERR_CODE error_code;
|
||||
#ifdef HEAD_OBJECT_FROM_REDIS
|
||||
redisAsyncContext *redis_ac;
|
||||
char redis_key[256];
|
||||
char redis_ip[128];
|
||||
int redis_port;
|
||||
int redis_connecting;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct multipart_etag_list
|
||||
@@ -146,7 +157,7 @@ void tango_cache_set_fail_state(struct tango_cache_ctx *ctx, enum CACHE_ERR_CODE
|
||||
const char *tango_cache_get_errstring(const struct tango_cache_ctx *ctx);
|
||||
|
||||
struct tango_cache_ctx *tango_cache_update_prepare(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_put *meta);
|
||||
struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta);
|
||||
struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *instance, enum CACHE_REQUEST_METHOD method, struct future* f, struct tango_cache_meta_get *meta);
|
||||
struct tango_cache_ctx *tango_cache_delete_prepare(struct tango_cache_instance *instance, struct future* f, const char *objkey);
|
||||
|
||||
#endif
|
||||
|
||||
243
cache/src/tango_cache_redis.cpp
vendored
Normal file
243
cache/src/tango_cache_redis.cpp
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hiredis/hiredis.h>
|
||||
#include <hiredis/async.h>
|
||||
#include <hiredis/adapters/libevent.h>
|
||||
|
||||
#include "tango_cache_transfer.h"
|
||||
#include "tango_cache_tools.h"
|
||||
#include "tango_cache_redis.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#define PARSE_JSON_RET_ERROR -1
|
||||
#define PARSE_JSON_RET_TIMEOUT 0
|
||||
#define PARSE_JSON_RET_SUCC 1
|
||||
|
||||
#define CACHE_REDIS_CONNECT_IDLE 0
|
||||
#define CACHE_REDIS_CONNECTING 1
|
||||
#define CACHE_REDIS_CONNECTED 2
|
||||
#define CACHE_REDIS_DISCONNECTED 3
|
||||
|
||||
struct http_hdr_name
|
||||
{
|
||||
const char *json_name;
|
||||
const char *http_name;
|
||||
};
|
||||
struct http_hdr_name g_http_hdr_name[HDR_CONTENT_NUM]=
|
||||
{
|
||||
{"content-type", "Content-Type: "},
|
||||
{"content-encoding", "Content-Encoding: "},
|
||||
{"content-disposition", "Content-Disposition: "},
|
||||
{"content-md5", "Content-MD5: "}
|
||||
};
|
||||
|
||||
void redis_asyn_disconnect_cb(const struct redisAsyncContext *ac, int status)
|
||||
{
|
||||
struct tango_cache_instance *instance = (struct tango_cache_instance *)redisAsyncGetConnectionData(ac);
|
||||
|
||||
if(status == REDIS_OK)
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_INFO, "Redis disconnect %s:%u success.", instance->redis_ip, instance->redis_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_INFO, "Redis disconnect %s:%u failed: %s.", instance->redis_ip, instance->redis_port, ac->errstr);
|
||||
}
|
||||
instance->redis_connecting = CACHE_REDIS_DISCONNECTED;
|
||||
}
|
||||
|
||||
void redis_asyn_connect_cb(const struct redisAsyncContext *ac, int status)
|
||||
{
|
||||
struct tango_cache_instance *instance = (struct tango_cache_instance *)redisAsyncGetConnectionData(ac);
|
||||
|
||||
if(status == REDIS_OK)
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_INFO, "Redis connect %s:%u success.", instance->redis_ip, instance->redis_port);
|
||||
instance->redis_connecting = CACHE_REDIS_CONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
MESA_HANDLE_RUNTIME_LOGV2(instance->runtime_log, RLOG_LV_INFO, "Redis connect %s:%u failed.", instance->redis_ip, instance->redis_port, ac->errstr);
|
||||
instance->redis_connecting = CACHE_REDIS_CONNECT_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
int redis_asyn_connect_init(struct tango_cache_instance *instance, const char *redisip, int redis_port)
|
||||
{
|
||||
instance->redis_ac = redisAsyncConnect(redisip, redis_port);
|
||||
if(instance->redis_ac == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
instance->redis_connecting = CACHE_REDIS_CONNECTING;
|
||||
redisLibeventAttach(instance->redis_ac, instance->evbase);
|
||||
redisAsyncSetConnectionData(instance->redis_ac, instance);
|
||||
redisAsyncSetConnectCallback(instance->redis_ac, redis_asyn_connect_cb);
|
||||
redisAsyncSetDisconnectCallback(instance->redis_ac, redis_asyn_disconnect_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_minio_events_json(struct tango_cache_ctx *ctx, const char *jcontent)
|
||||
{
|
||||
cJSON *root, *pobject = NULL, *ptarget, *plastMod, *pexpires;
|
||||
int ret = PARSE_JSON_RET_ERROR;
|
||||
char usertag[2048];
|
||||
size_t datalen;
|
||||
|
||||
//Records[0]->s3->object->key...userMetaData->metas...
|
||||
if(NULL == (root=cJSON_Parse(jcontent)))
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
if(NULL==(pobject=cJSON_GetObjectItem(root, "Records")) || pobject->type!=cJSON_Array)
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
if(NULL == (pobject=cJSON_GetArrayItem(pobject, 0))) //<2F><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>أ<EFBFBD>һ<EFBFBD><D2BB>ֻ<EFBFBD><D6BB>һ<EFBFBD><D2BB>
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
if(NULL == (pobject=cJSON_GetObjectItem(pobject, "s3")) || pobject->type!=cJSON_Object)
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
if(NULL == (pobject=cJSON_GetObjectItem(pobject, "object")) || pobject->type!=cJSON_Object)
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
|
||||
if(NULL == (ptarget=cJSON_GetObjectItem(pobject, "size")) || ptarget->type!=cJSON_Number)
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
ctx->get.result.tlength = ptarget->valueint; //TODO: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4GB<47><42>ô<EFBFBD>죿
|
||||
if(NULL == (ptarget=cJSON_GetObjectItem(pobject, "userMetadata")) || ptarget->type!=cJSON_Object)
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
if(NULL==(plastMod=cJSON_GetObjectItem(ptarget, "X-Amz-Meta-Lm")) || NULL==(pexpires=cJSON_GetObjectItem(ptarget, "expires")))
|
||||
{
|
||||
goto out_json;
|
||||
}
|
||||
ctx->get.need_hdrs = RESPONSE_HDR_ALL;
|
||||
ctx->get.last_modify = atol(plastMod->valuestring);
|
||||
ctx->get.expires = expires_hdr2timestamp(pexpires->valuestring, strlen(pexpires->valuestring));
|
||||
if(!check_expires_fresh_header(ctx))
|
||||
{
|
||||
ret = PARSE_JSON_RET_TIMEOUT;
|
||||
goto out_json;
|
||||
}
|
||||
|
||||
if(NULL!=(plastMod=cJSON_GetObjectItem(ptarget, "X-Amz-Meta-User")))
|
||||
{
|
||||
if((datalen = Base64_DecodeBlock((unsigned char*)plastMod->valuestring, strlen(plastMod->valuestring), (unsigned char*)usertag, 2048))>0)
|
||||
{
|
||||
easy_string_savedata(&ctx->get.response_tag, usertag, datalen);
|
||||
}
|
||||
}
|
||||
for(int i=0; i<HDR_CONTENT_NUM; i++)
|
||||
{
|
||||
if(NULL != (plastMod=cJSON_GetObjectItem(ptarget, g_http_hdr_name[i].json_name)))
|
||||
{
|
||||
easy_string_savedata(&ctx->response, g_http_hdr_name[i].http_name, strlen(g_http_hdr_name[i].http_name));
|
||||
easy_string_savedata(&ctx->response, plastMod->valuestring, strlen(plastMod->valuestring));
|
||||
easy_string_savedata(&ctx->response, "\r\n", strlen("\r\n"));
|
||||
}
|
||||
}
|
||||
return PARSE_JSON_RET_SUCC;
|
||||
|
||||
out_json:
|
||||
cJSON_Delete(root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void redis_hget_command_cb(struct redisAsyncContext *ac, void *vreply, void *privdata)
|
||||
{
|
||||
redisReply *reply = (redisReply *)vreply;
|
||||
struct tango_cache_ctx *ctx = (struct tango_cache_ctx *)privdata;
|
||||
int ret;
|
||||
|
||||
if(reply == NULL || reply->type!=REDIS_REPLY_STRING)
|
||||
{
|
||||
if(reply->type == REDIS_REPLY_NIL)
|
||||
{
|
||||
tango_cache_set_fail_state(ctx, CACHE_CACHE_MISS);
|
||||
ctx->get.result.type = RESULT_TYPE_MISS;
|
||||
promise_success(future_to_promise(ctx->future), &ctx->get.result);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ac->err) MESA_HANDLE_RUNTIME_LOGV2(ctx->instance->runtime_log, RLOG_LV_FATAL, "redis_hget_command_cb error: %s.", ac->errstr);
|
||||
tango_cache_set_fail_state(ctx, CACHE_ERR_REDIS_JSON);
|
||||
promise_failed(future_to_promise(ctx->future), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx));
|
||||
}
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = parse_minio_events_json(ctx, reply->str);
|
||||
switch(ret)
|
||||
{
|
||||
case PARSE_JSON_RET_ERROR:
|
||||
tango_cache_set_fail_state(ctx, CACHE_ERR_REDIS_JSON);
|
||||
promise_failed(future_to_promise(ctx->future), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx));
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
break;
|
||||
case PARSE_JSON_RET_TIMEOUT:
|
||||
if(ctx->get.state == GET_STATE_DELETE)
|
||||
{
|
||||
ctx->get.state = GET_STATE_END;
|
||||
cache_delete_minio_object(ctx);
|
||||
}
|
||||
break;
|
||||
case PARSE_JSON_RET_SUCC:
|
||||
fetch_header_over_biz(ctx);
|
||||
ctx->get.result.type = RESULT_TYPE_END;
|
||||
promise_success(future_to_promise(ctx->future), &ctx->get.result);
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
break;
|
||||
default: assert(0);break;
|
||||
}
|
||||
}
|
||||
|
||||
int tango_cache_head_redis(struct tango_cache_ctx *ctx)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
ctx->instance->statistic.get_recv_num += 1;
|
||||
switch(ctx->instance->redis_connecting)
|
||||
{
|
||||
case CACHE_REDIS_CONNECTED:
|
||||
ret = redisAsyncCommand(ctx->instance->redis_ac, redis_hget_command_cb, ctx, "HGET %s %s/%s",
|
||||
ctx->instance->redis_key, ctx->instance->bucketname, ctx->object_key);
|
||||
if(ret < 0)
|
||||
{
|
||||
redisAsyncDisconnect(ctx->instance->redis_ac);
|
||||
redis_asyn_connect_init(ctx->instance, ctx->instance->redis_ip, ctx->instance->redis_port);
|
||||
tango_cache_set_fail_state(ctx, CACHE_ERR_REDIS_CONNECT);
|
||||
promise_failed(future_to_promise(ctx->future), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx));
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
}
|
||||
break;
|
||||
case CACHE_REDIS_DISCONNECTED:
|
||||
case CACHE_REDIS_CONNECT_IDLE:
|
||||
redis_asyn_connect_init(ctx->instance, ctx->instance->redis_ip, ctx->instance->redis_port);
|
||||
case CACHE_REDIS_CONNECTING:
|
||||
tango_cache_set_fail_state(ctx, CACHE_ERR_REDIS_CONNECT);
|
||||
promise_failed(future_to_promise(ctx->future), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx));
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
break;
|
||||
default: assert(0);break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
13
cache/src/tango_cache_redis.h
vendored
Normal file
13
cache/src/tango_cache_redis.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __TANGO_CACHE_REDIS_H__
|
||||
#define __TANGO_CACHE_REDIS_H__
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <event.h>
|
||||
|
||||
#include "tango_cache_client_in.h"
|
||||
|
||||
int tango_cache_head_redis(struct tango_cache_ctx *ctx);
|
||||
int redis_asyn_connect_init(struct tango_cache_instance *instance, const char *redisip, int redis_port);
|
||||
|
||||
#endif
|
||||
|
||||
85
cache/src/tango_cache_transfer.cpp
vendored
85
cache/src/tango_cache_transfer.cpp
vendored
@@ -174,7 +174,6 @@ int curl_get_minio_uploadID(struct tango_cache_ctx *ctx)
|
||||
|
||||
if(NULL == (ctx->curl=curl_easy_init()))
|
||||
{
|
||||
free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -209,6 +208,7 @@ int cache_delete_minio_object(struct tango_cache_ctx *ctx)
|
||||
ctx->instance->statistic.del_recv_num += 1;
|
||||
if(NULL == (ctx->curl=curl_easy_init()))
|
||||
{
|
||||
tango_cache_ctx_destroy(ctx); //<2F>ս<EFBFBD><D5BD><EFBFBD>
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ int cache_kick_upload_minio_end(struct tango_cache_ctx *ctx)
|
||||
switch(ctx->put.state)
|
||||
{
|
||||
case PUT_STATE_START:
|
||||
http_put_complete_part_evbuf(ctx);
|
||||
ret = http_put_complete_part_evbuf(ctx);
|
||||
break;
|
||||
|
||||
case PUT_STATE_PART:
|
||||
@@ -652,24 +652,16 @@ int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static size_t curl_get_response_body_cb(void *ptr, size_t size, size_t count, void *userp)
|
||||
bool fetch_header_over_biz(struct tango_cache_ctx *ctx)
|
||||
{
|
||||
struct tango_cache_ctx *ctx = (struct tango_cache_ctx *)userp;
|
||||
|
||||
if(ctx->fail_state || ctx->get.state==GET_STATE_DELETE)
|
||||
{
|
||||
return size*count;
|
||||
}
|
||||
|
||||
if(ctx->get.need_hdrs!=RESPONSE_HDR_ALL) //<2F><>Expiresʱ
|
||||
{
|
||||
tango_cache_set_fail_state(ctx, CACHE_ERR_INTERNAL);
|
||||
ctx->get.state = GET_STATE_DELETE;
|
||||
promise_failed(future_to_promise(ctx->future), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx));
|
||||
return size*count;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(ctx->get.response_tag.len > 0)
|
||||
{
|
||||
ctx->get.result.data_frag = ctx->get.response_tag.buff;
|
||||
@@ -686,6 +678,23 @@ static size_t curl_get_response_body_cb(void *ptr, size_t size, size_t count, vo
|
||||
promise_success(future_to_promise(ctx->future), &ctx->get.result);
|
||||
easy_string_destroy(&ctx->response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t curl_get_response_body_cb(void *ptr, size_t size, size_t count, void *userp)
|
||||
{
|
||||
struct tango_cache_ctx *ctx = (struct tango_cache_ctx *)userp;
|
||||
|
||||
if(ctx->fail_state || ctx->get.state==GET_STATE_DELETE)
|
||||
{
|
||||
return size*count;
|
||||
}
|
||||
|
||||
if(!fetch_header_over_biz(ctx))
|
||||
{
|
||||
return size*count;
|
||||
}
|
||||
|
||||
ctx->get.result.data_frag = (const char *)ptr;
|
||||
ctx->get.result.size = size * count;
|
||||
ctx->get.result.type = RESULT_TYPE_BODY;
|
||||
@@ -693,14 +702,16 @@ static size_t curl_get_response_body_cb(void *ptr, size_t size, size_t count, vo
|
||||
return size*count;
|
||||
}
|
||||
|
||||
static bool check_expires_header(struct tango_cache_ctx *ctx, const char *expires_val, size_t len)
|
||||
bool check_expires_fresh_header(struct tango_cache_ctx *ctx)
|
||||
{
|
||||
time_t time_gmt;
|
||||
time_t now_gmt;
|
||||
|
||||
ctx->get.expires = expires_hdr2timestamp(expires_val, len);
|
||||
time_gmt = get_gmtime_timestamp(time(NULL));
|
||||
if(ctx->get.need_hdrs != RESPONSE_HDR_ALL)
|
||||
return true;
|
||||
|
||||
now_gmt = get_gmtime_timestamp(time(NULL));
|
||||
|
||||
if(time_gmt > ctx->get.expires)
|
||||
if(now_gmt > ctx->get.expires)
|
||||
{
|
||||
tango_cache_set_fail_state(ctx, CACHE_TIMEOUT);
|
||||
ctx->get.state = GET_STATE_DELETE; //<2F><><EFBFBD><EFBFBD>ʧЧʱ<D0A7><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
@@ -709,17 +720,7 @@ static bool check_expires_header(struct tango_cache_ctx *ctx, const char *expire
|
||||
easy_string_destroy(&ctx->response);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_fresh_header(struct tango_cache_ctx *ctx)
|
||||
{
|
||||
time_t now_gmt;
|
||||
|
||||
if(ctx->get.need_hdrs != RESPONSE_HDR_ALL)
|
||||
return true;
|
||||
|
||||
now_gmt = get_gmtime_timestamp(time(NULL));
|
||||
|
||||
if(ctx->get.last_modify+ctx->get.max_age > now_gmt || now_gmt+ctx->get.min_fresh>ctx->get.expires)
|
||||
{
|
||||
tango_cache_set_fail_state(ctx, CACHE_TIMEOUT);
|
||||
@@ -791,7 +792,8 @@ static size_t curl_get_response_header_cb(void *ptr, size_t size, size_t count,
|
||||
if(strcmp_one_word_mesa_equal_len("expires", "EXPIRES", start, 7))
|
||||
{
|
||||
ctx->get.need_hdrs |= RESPONSE_HDR_EXPIRES;
|
||||
if(!check_expires_header(ctx, pos_colon + 1, raw_len - datalen - 1) || !check_fresh_header(ctx))
|
||||
ctx->get.expires = expires_hdr2timestamp(pos_colon + 1, raw_len - datalen - 1);
|
||||
if(!check_expires_fresh_header(ctx))
|
||||
{
|
||||
return raw_len;
|
||||
}
|
||||
@@ -802,7 +804,7 @@ static size_t curl_get_response_header_cb(void *ptr, size_t size, size_t count,
|
||||
{
|
||||
ctx->get.need_hdrs |= RESPONSE_HDR_LAST_MOD;
|
||||
sscanf(pos_colon+1, "%lu", &ctx->get.last_modify);
|
||||
if(!check_fresh_header(ctx))
|
||||
if(!check_expires_fresh_header(ctx))
|
||||
{
|
||||
return raw_len;
|
||||
}
|
||||
@@ -839,21 +841,18 @@ void tango_cache_curl_get_done(struct tango_cache_ctx *ctx, CURLcode res, long r
|
||||
case GET_STATE_START:
|
||||
if(!ctx->fail_state && check_get_result_code(ctx, res, res_code))
|
||||
{
|
||||
ctx->get.result.type = RESULT_TYPE_END;
|
||||
promise_success(future_to_promise(ctx->future), &ctx->get.result);
|
||||
if(ctx->method!=CACHE_REQUEST_HEAD || fetch_header_over_biz(ctx)) //HEAD<41><44><EFBFBD>ֵ<EFBFBD><D6B5>ֶβ<D6B6>ȫ<EFBFBD>Ȳ<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ޣ<EFBFBD>
|
||||
{
|
||||
ctx->get.result.type = RESULT_TYPE_END;
|
||||
promise_success(future_to_promise(ctx->future), &ctx->get.result);
|
||||
}
|
||||
}
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
break;
|
||||
|
||||
case GET_STATE_DELETE:
|
||||
if(cache_delete_minio_object(ctx))
|
||||
{
|
||||
ctx->get.state = GET_STATE_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
tango_cache_ctx_destroy(ctx);
|
||||
}
|
||||
ctx->get.state = GET_STATE_END;
|
||||
cache_delete_minio_object(ctx);
|
||||
break;
|
||||
|
||||
case GET_STATE_END:
|
||||
@@ -877,6 +876,10 @@ int tango_cache_fetch_start(struct tango_cache_ctx *ctx)
|
||||
|
||||
snprintf(minio_url, 256, "http://%s/%s/%s", ctx->hostaddr, ctx->instance->bucketname, ctx->object_key);
|
||||
curl_easy_setopt(ctx->curl, CURLOPT_URL, minio_url);
|
||||
if(ctx->method == CACHE_REQUEST_HEAD)
|
||||
{
|
||||
curl_easy_setopt(ctx->curl, CURLOPT_NOBODY, 1L);
|
||||
}
|
||||
curl_easy_setopt(ctx->curl, CURLOPT_USERAGENT, "aws-sdk-cpp/1.5.24 Linux/3.10.0-327.el7.x86_64 x86_64 pangu_cache");
|
||||
curl_easy_setopt(ctx->curl, CURLOPT_NOSIGNAL,1L);
|
||||
curl_easy_setopt(ctx->curl, CURLOPT_WRITEFUNCTION, curl_get_response_body_cb);
|
||||
|
||||
3
cache/src/tango_cache_transfer.h
vendored
3
cache/src/tango_cache_transfer.h
vendored
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "tango_cache_client_in.h"
|
||||
|
||||
bool check_expires_fresh_header(struct tango_cache_ctx *ctx);
|
||||
bool fetch_header_over_biz(struct tango_cache_ctx *ctx);
|
||||
|
||||
void tango_cache_curl_put_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code);
|
||||
void tango_cache_curl_get_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code);
|
||||
void tango_cache_curl_del_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code);
|
||||
|
||||
49
cache/test/cache_evbase_test.cpp
vendored
49
cache/test/cache_evbase_test.cpp
vendored
@@ -68,6 +68,43 @@ void get_future_failed(enum e_future_error err, const char * what, void * user)
|
||||
runing_over = 2;
|
||||
}
|
||||
|
||||
void head_future_success(future_result_t* result, void * user)
|
||||
{
|
||||
struct tango_cache_result *res = cache_evbase_read_result(result);
|
||||
struct future_pdata *pdata = (struct future_pdata *)user;
|
||||
char buffer[1024];
|
||||
|
||||
switch(res->type)
|
||||
{
|
||||
case RESULT_TYPE_USERTAG:
|
||||
case RESULT_TYPE_HEADER:
|
||||
memcpy(buffer, res->data_frag, res->size>=1024?1023:res->size);
|
||||
buffer[res->size] = '\0';
|
||||
printf("%s", buffer);
|
||||
break;
|
||||
case RESULT_TYPE_BODY:
|
||||
assert(0);
|
||||
break;
|
||||
case RESULT_TYPE_MISS:
|
||||
printf("cache not hit/fresh\n");
|
||||
case RESULT_TYPE_END:
|
||||
if(res->type != RESULT_TYPE_MISS)
|
||||
printf("HEAD cache over, total length: %ld\n", res->tlength);
|
||||
future_destroy(pdata->future);
|
||||
free(pdata);
|
||||
runing_over = 1;
|
||||
break;
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
|
||||
void head_future_failed(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
printf("HEAD fail: %s\n", what);
|
||||
runing_over = 2;
|
||||
}
|
||||
|
||||
|
||||
void put_future_success(future_result_t* result, void * user)
|
||||
{
|
||||
struct future_pdata *pdata = (struct future_pdata *)user;
|
||||
@@ -201,15 +238,18 @@ int main(int argc, char **argv)
|
||||
{
|
||||
sprintf(filename_out, "file_index_%u.bin", index);
|
||||
pdata->future = future_create(get_future_success, get_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
pdata->fp = fopen(filename_out, "w");
|
||||
|
||||
cache_evbase_fetch_object(instance_asyn, pdata->future, &getmeta);
|
||||
}
|
||||
else if(!strcasecmp(p, "HEAD"))
|
||||
{
|
||||
pdata->future = future_create(head_future_success, head_future_failed, pdata);
|
||||
cache_evbase_head_object(instance_asyn, pdata->future, &getmeta);
|
||||
}
|
||||
else if(!strcasecmp(p, "DEL"))
|
||||
{
|
||||
pdata->future = future_create(del_future_success, del_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
sprintf(pdata->filename, "%s", filename_in);
|
||||
cache_evbase_delete_object(instance_asyn, pdata->future, filename_in);
|
||||
}
|
||||
@@ -218,7 +258,6 @@ int main(int argc, char **argv)
|
||||
size_t filelen;
|
||||
p = get_file_content(filename_in, &filelen);
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
|
||||
cache_evbase_upload_once_data(instance_asyn, pdata->future, PUT_MEM_FREE, p, filelen, &putmeta, pdata->filename, 256);
|
||||
}
|
||||
@@ -226,7 +265,6 @@ int main(int argc, char **argv)
|
||||
{
|
||||
size_t readlen;
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
struct evbuffer *evbuf = evbuffer_new();
|
||||
char buffer[1024];
|
||||
|
||||
@@ -246,7 +284,6 @@ int main(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
|
||||
ctx = cache_evbase_update_start(instance_asyn, pdata->future, &putmeta);
|
||||
cache_evbase_get_object_path(ctx, pdata->filename, 256);
|
||||
@@ -265,7 +302,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
printf("Waiting to finish.......\n");
|
||||
static int num=0;
|
||||
//static int num=0;
|
||||
while(!runing_over)
|
||||
{
|
||||
/*if(++num==10)
|
||||
|
||||
49
cache/test/tango_cache_test.c
vendored
49
cache/test/tango_cache_test.c
vendored
@@ -79,6 +79,40 @@ void get_future_failed(enum e_future_error err, const char * what, void * user)
|
||||
printf("GET fail: %s\n", what);
|
||||
}
|
||||
|
||||
void head_future_success(future_result_t* result, void * user)
|
||||
{
|
||||
struct tango_cache_result *res = tango_cache_read_result(result);
|
||||
struct future_pdata *pdata = (struct future_pdata *)user;
|
||||
char buffer[1024];
|
||||
|
||||
switch(res->type)
|
||||
{
|
||||
case RESULT_TYPE_USERTAG:
|
||||
case RESULT_TYPE_HEADER:
|
||||
memcpy(buffer, res->data_frag, res->size>=1024?1023:res->size);
|
||||
buffer[res->size] = '\0';
|
||||
printf("%s", buffer);
|
||||
break;
|
||||
case RESULT_TYPE_BODY:
|
||||
assert(0);
|
||||
break;
|
||||
case RESULT_TYPE_MISS:
|
||||
printf("cache not hit/fresh\n");
|
||||
case RESULT_TYPE_END:
|
||||
if(res->type != RESULT_TYPE_MISS)
|
||||
printf("HEAD cache over, total length: %ld\n", res->tlength);
|
||||
future_destroy(pdata->future);
|
||||
free(pdata);
|
||||
break;
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
|
||||
void head_future_failed(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
printf("HEAD fail: %s\n", what);
|
||||
}
|
||||
|
||||
void put_future_success(future_result_t* result, void * user)
|
||||
{
|
||||
struct future_pdata *pdata = (struct future_pdata *)user;
|
||||
@@ -182,6 +216,7 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg)
|
||||
p = method;
|
||||
|
||||
memset(&putmeta, 0, sizeof(struct tango_cache_meta_put));
|
||||
memset(&getmeta, 0, sizeof(struct tango_cache_meta_get));
|
||||
putmeta.url = s;
|
||||
putmeta.std_hdr[HDR_CONTENT_TYPE] = "Content-Type: maintype/subtype";
|
||||
putmeta.std_hdr[HDR_CONTENT_ENCODING] = "Content-Encoding: gzip";
|
||||
@@ -197,16 +232,22 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg)
|
||||
sprintf(filename, "file_index_%u.bin", index++);
|
||||
pdata->fp = fopen(filename, "w");
|
||||
pdata->future = future_create(get_future_success, get_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
|
||||
tango_cache_fetch_object(tango_instance, pdata->future, &getmeta);
|
||||
}
|
||||
else if(!strcasecmp(p, "HEAD"))
|
||||
{
|
||||
sprintf(filename, "file_index_%u.bin", index++);
|
||||
pdata->fp = fopen(filename, "w");
|
||||
pdata->future = future_create(head_future_success, head_future_failed, pdata);
|
||||
|
||||
tango_cache_head_object(tango_instance, pdata->future, &getmeta);
|
||||
}
|
||||
else if(!strcasecmp(p, "PUTONCE"))
|
||||
{
|
||||
size_t filelen;
|
||||
p = get_file_content(s, &filelen);
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
|
||||
tango_cache_upload_once_data(tango_instance, pdata->future, PUT_MEM_FREE, p, filelen, &putmeta, pdata->filename, 256);
|
||||
}
|
||||
@@ -214,7 +255,6 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg)
|
||||
{
|
||||
size_t readlen;
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
struct evbuffer *evbuf = evbuffer_new();
|
||||
char buffer[1024];
|
||||
|
||||
@@ -234,14 +274,12 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg)
|
||||
else if(!strcasecmp(p, "DEL"))
|
||||
{
|
||||
pdata->future = future_create(del_future_success, del_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
sprintf(pdata->filename, "%s", s);
|
||||
tango_cache_delete_object(tango_instance, pdata->future, s);
|
||||
}
|
||||
else if(!strcasecmp(p, "DELMUL")) //TODO
|
||||
{
|
||||
pdata->future = future_create(del_future_success, del_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
sprintf(pdata->filename, "%s", s);
|
||||
|
||||
for(pstart = strtok_r(s, ";", &save_ptr); pstart != NULL; pstart = strtok_r(NULL, ";", &save_ptr))
|
||||
@@ -253,7 +291,6 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg)
|
||||
else
|
||||
{
|
||||
pdata->future = future_create(put_future_success, put_future_failed, pdata);
|
||||
promise_set_ctx(future_to_promise(pdata->future), NULL, NULL);
|
||||
|
||||
ctx = tango_cache_update_start(tango_instance, pdata->future, &putmeta);
|
||||
tango_cache_get_object_path(ctx, pdata->filename, 256);
|
||||
|
||||
BIN
vendor/hiredis-master.zip
vendored
Normal file
BIN
vendor/hiredis-master.zip
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user