From e1ad321332940f1432deb4c4f629f76f1b93ed0d Mon Sep 17 00:00:00 2001 From: zhangchengwei Date: Sat, 27 Oct 2018 11:03:58 +0800 Subject: [PATCH] =?UTF-8?q?[1]=E7=BB=9F=E4=B8=80GET/PUT=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E5=90=8E=E7=BB=93=E6=9E=9C=E9=80=9A=E7=9F=A5=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=EF=BC=8CAPI=E7=9B=B4=E6=8E=A5=E8=B0=83=E7=94=A8=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=97=B6=E4=B8=8D=E5=9B=9E=E8=B0=83=EF=BC=8C=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E6=83=85=E5=86=B5=E5=9B=9E=E8=B0=83(promise)=EF=BC=9B?= =?UTF-8?q?=20[2]hiredis=E7=89=88=E6=9C=AC=E7=A1=AE=E5=AE=9A=E4=B8=BA0.14.?= =?UTF-8?q?0=E7=89=88=EF=BC=9B=20[3]=E4=BF=AE=E5=A4=8Dtango=5Fcache=5Fctx?= =?UTF-8?q?=5Fdestroy=E4=B8=ADTAILQ=E5=86=85=E5=AD=98=E9=87=8A=E6=94=BE?= =?UTF-8?q?=E7=9A=84BUG=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cache/README.txt | 6 +- cache/include/tango_cache_client.h | 3 +- cache/src/cache_evbase_client.cpp | 55 +++++++------ cache/src/tango_cache_client.cpp | 41 ++++++++-- cache/src/tango_cache_client_in.h | 5 +- cache/src/tango_cache_redis.cpp | 10 +-- cache/src/tango_cache_transfer.cpp | 75 +++++++++--------- cache/src/tango_cache_transfer.h | 10 +-- cache/test/lib/libhiredis.a | Bin 460556 -> 460438 bytes cache/test/tango_cache_test.c | 35 ++++++-- ...0.14.0-modified.zip => hiredis-0.14.0.zip} | Bin 93217 -> 93219 bytes 11 files changed, 150 insertions(+), 90 deletions(-) rename vendor/{hiredis-0.14.0-modified.zip => hiredis-0.14.0.zip} (75%) diff --git a/cache/README.txt b/cache/README.txt index 62589e8..1360813 100644 --- a/cache/README.txt +++ b/cache/README.txt @@ -1,3 +1,3 @@ -1、HEAD操作支持从minio和redis两种渠道获取,默认情况下从minio获取。 -2、若想从redis获取,编译时加宏定义-DHEAD_OBJECT_FROM_REDIS -3、使用的redis客户端是自己修改过的版本(support下提供)。 +1、HEAD操作支持从minio和redis两种渠道获取,根据配置文件决定。 + +2、使用的redis客户端是自己修改过的版本(vendor下提供)。 diff --git a/cache/include/tango_cache_client.h b/cache/include/tango_cache_client.h index 1e45187..df60254 100644 --- a/cache/include/tango_cache_client.h +++ b/cache/include/tango_cache_client.h @@ -21,6 +21,7 @@ enum CACHE_ERR_CODE CACHE_ERR_INTERNAL, CACHE_ERR_REDIS_JSON, CACHE_ERR_REDIS_CONNECT, + CACHE_OUTOF_SESSION, }; enum PUT_MEMORY_COPY_WAY @@ -81,7 +82,7 @@ enum CACHE_HTTP_HDR_TYPE struct tango_cache_meta_get { - const char* url; //缓存:URI;非结构化日志:文件路径名。不要以'/'开头;CACHE_OBJECT_KEY_HASH_SWITCH=0时最大长度256字节,=1时无限制 + const char* url; //缓存:URL;非结构化日志:文件路径名。CACHE_OBJECT_KEY_HASH_SWITCH=0时最大长度256字节,=1时无限制 struct request_freshness get; }; diff --git a/cache/src/cache_evbase_client.cpp b/cache/src/cache_evbase_client.cpp index 4ce8799..5383384 100644 --- a/cache/src/cache_evbase_client.cpp +++ b/cache/src/cache_evbase_client.cpp @@ -153,36 +153,47 @@ static void cache_asyn_ctx_destroy(struct cache_evbase_ctx *ctx_asyn) static void cache_asyn_ioevent_dispatch(struct databuffer *buffer) { struct cache_evbase_ctx *ctx_asyn=buffer->ctx_asyn; + struct future *f; + int ret=0; switch(buffer->cmd_type) { case CACHE_ASYN_FETCH: - tango_cache_fetch_start(ctx_asyn->ctx); + f = ctx_asyn->ctx->future; + if(tango_cache_fetch_start(ctx_asyn->ctx) < 0) + { + promise_failed(future_to_promise(f), FUTURE_ERROR_CANCEL, "CACHE_ASYN_FETCH failed"); + } cache_asyn_ctx_destroy(ctx_asyn); break; case CACHE_ASYN_HEAD: + f = ctx_asyn->ctx->future; if(ctx_asyn->instance_asyn->instance->head_meta_source == HEAD_META_FROM_REDIS) { - tango_cache_head_redis(ctx_asyn->ctx); + ret = tango_cache_head_redis(ctx_asyn->ctx); } else { - tango_cache_fetch_start(ctx_asyn->ctx); - } + ret = tango_cache_fetch_start(ctx_asyn->ctx); + } + if(ret<0) + { + promise_failed(future_to_promise(f), FUTURE_ERROR_CANCEL, "CACHE_ASYN_HEAD failed"); + } cache_asyn_ctx_destroy(ctx_asyn); break; case CACHE_ASYN_DELETE: - cache_delete_minio_object(ctx_asyn->ctx); + cache_delete_minio_object(ctx_asyn->ctx, true); cache_asyn_ctx_destroy(ctx_asyn); break; case CACHE_ASYN_UPLOAD_ONCE_DATA: - tango_cache_upload_once_start_data(ctx_asyn->ctx, PUT_MEM_FREE, buffer->data, buffer->size); + tango_cache_upload_once_start_data(ctx_asyn->ctx, PUT_MEM_FREE, buffer->data, buffer->size, true); cache_asyn_ctx_destroy(ctx_asyn); break; case CACHE_ASYN_UPLOAD_ONCE_EVBUF: - tango_cache_upload_once_start_evbuf(ctx_asyn->ctx, EVBUFFER_MOVE, buffer->evbuf); + tango_cache_upload_once_start_evbuf(ctx_asyn->ctx, EVBUFFER_MOVE, buffer->evbuf, true); evbuffer_free(buffer->evbuf); cache_asyn_ctx_destroy(ctx_asyn); break; @@ -361,8 +372,8 @@ struct cache_evbase_ctx *cache_evbase_update_start(struct cache_evbase_instance //事件通知仅为了增加统计信息 if(iothread_notify_event(instance->notify_sendfd, &buffer, sizeof(void *), 2) != sizeof(void *)) { - tango_cache_set_fail_state(ctx_asyn->ctx, CACHE_ERR_SOCKPAIR); - tango_cache_ctx_destroy(ctx_asyn->ctx); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx_asyn->ctx, false); cache_asyn_ctx_destroy(ctx_asyn); free(buffer); return NULL; @@ -409,8 +420,8 @@ int cache_evbase_upload_once_data(struct cache_evbase_instance *instance, struct { free(buffer->data); free(buffer); - tango_cache_set_fail_state(ctx_asyn->ctx, CACHE_ERR_SOCKPAIR); - tango_cache_ctx_destroy(ctx); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx, false); cache_asyn_ctx_destroy(ctx_asyn); return -2; } @@ -448,8 +459,8 @@ int cache_evbase_upload_once_evbuf(struct cache_evbase_instance *instance, struc { evbuffer_free(buffer->evbuf); free(buffer); - tango_cache_set_fail_state(ctx_asyn->ctx, CACHE_ERR_SOCKPAIR); - tango_cache_ctx_destroy(ctx); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx, false); cache_asyn_ctx_destroy(ctx_asyn); return -2; } @@ -476,9 +487,8 @@ int cache_evbase_fetch_object(struct cache_evbase_instance *instance, struct fut 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); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx_asyn->ctx, false); cache_asyn_ctx_destroy(ctx_asyn); free(buffer); return -2; @@ -506,9 +516,8 @@ int cache_evbase_head_object(struct cache_evbase_instance *instance, struct futu 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); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx_asyn->ctx, false); cache_asyn_ctx_destroy(ctx_asyn); free(buffer); return -2; @@ -537,12 +546,8 @@ int cache_evbase_delete_object(struct cache_evbase_instance *instance, struct fu //参考Unix高级编程432页关于多线程写的安全性描述 if(iothread_notify_event(instance->notify_sendfd, &buffer, sizeof(void *), 2) != sizeof(void *)) { - tango_cache_set_fail_state(ctx_asyn->ctx, CACHE_ERR_SOCKPAIR); - if(f != NULL) - { - promise_failed(future_to_promise(f), FUTURE_ERROR_CANCEL, tango_cache_get_errstring(ctx_asyn->ctx)); - } - tango_cache_ctx_destroy(ctx_asyn->ctx); + instance->instance->error_code = CACHE_ERR_SOCKPAIR; + tango_cache_ctx_destroy(ctx_asyn->ctx, false); cache_asyn_ctx_destroy(ctx_asyn); free(buffer); return -2; diff --git a/cache/src/tango_cache_client.cpp b/cache/src/tango_cache_client.cpp index 0efec36..c6fa89d 100644 --- a/cache/src/tango_cache_client.cpp +++ b/cache/src/tango_cache_client.cpp @@ -94,6 +94,7 @@ const char *tango_cache_get_errstring(const struct tango_cache_ctx *ctx) 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"; + case CACHE_OUTOF_SESSION:return "two many curl sessions"; default: return ctx->error; } } @@ -194,7 +195,8 @@ void easy_string_savedata(struct easy_string *estr, const char *data, size_t len estr->buff[estr->len]='\0'; } -void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx) +//callback: 是否调用回调函数,主要为解决直接调用API时失败,不再调用回调,而是通过返回值判断 +void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx, bool callback) { struct multipart_etag_list *etag; @@ -220,7 +222,7 @@ void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx) ctx->instance->statistic.memory_used -= evbuffer_get_length(ctx->put.evbuf); evbuffer_free(ctx->put.evbuf); } - TAILQ_FOREACH(etag, &ctx->put.etag_head, node) + while(NULL != (etag = TAILQ_FIRST(&ctx->put.etag_head))) { TAILQ_REMOVE(&ctx->put.etag_head, etag, node); free(etag->etag); @@ -232,7 +234,7 @@ void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx) curl_slist_free_all(ctx->headers); }//no break here case CACHE_REQUEST_DELETE: - if(ctx->future != NULL) + if(callback && ctx->future != NULL) { if(ctx->fail_state) { @@ -263,6 +265,7 @@ int tango_cache_update_frag_data(struct tango_cache_ctx *ctx, const char *data, } if(evbuffer_add(ctx->put.evbuf, data, size)) { + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); return -1; } ctx->instance->statistic.memory_used += size; @@ -287,6 +290,7 @@ int tango_cache_update_frag_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COP { if(evbuffer_add_buffer(ctx->put.evbuf, evbuf)) { + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); return -1; } } @@ -294,6 +298,7 @@ int tango_cache_update_frag_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COP { if(evbuffer_add_buffer_reference(ctx->put.evbuf, evbuf)) { + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); return -1; } } @@ -311,7 +316,7 @@ struct tango_cache_ctx *tango_cache_update_prepare(struct tango_cache_instance * char buffer[2064]; time_t expires, now, last_modify; - if((u_int64_t)instance->statistic.memory_used >= instance->cache_limit_size) + if((u_int64_t)instance->statistic.memory_used>=instance->cache_limit_size || instance->statistic.session_num>=instance->max_session_num) { instance->error_code = CACHE_OUTOF_MEMORY; instance->statistic.totaldrop_num += 1; @@ -441,6 +446,13 @@ struct tango_cache_ctx *tango_cache_fetch_prepare(struct tango_cache_instance *i struct tango_cache_ctx *ctx; char sha256[72]; + if(instance->head_meta_source!=HEAD_META_FROM_REDIS && instance->statistic.session_num>=instance->max_session_num) + { + instance->error_code = CACHE_OUTOF_SESSION; + instance->statistic.totaldrop_num += 1; + return NULL; + } + ctx = (struct tango_cache_ctx *)calloc(1, sizeof(struct tango_cache_ctx)); ctx->instance = instance; ctx->future = f; @@ -477,7 +489,7 @@ int tango_cache_fetch_object(struct tango_cache_instance *instance, struct futur { return -1; } - return tango_cache_fetch_start(ctx); + return (tango_cache_fetch_start(ctx)==1)?0:-1; } int tango_cache_head_object(struct tango_cache_instance *instance, struct future* f, struct tango_cache_meta_get *meta) @@ -496,7 +508,7 @@ int tango_cache_head_object(struct tango_cache_instance *instance, struct future } else { - return tango_cache_fetch_start(ctx); + return (tango_cache_fetch_start(ctx)==1)?0:-1; } } @@ -505,6 +517,13 @@ struct tango_cache_ctx *tango_cache_delete_prepare(struct tango_cache_instance * struct tango_cache_ctx *ctx; char sha256[72]; + if(instance->statistic.session_num >= instance->max_session_num) + { + instance->error_code = CACHE_OUTOF_SESSION; + instance->statistic.totaldrop_num += 1; + return NULL; + } + ctx = (struct tango_cache_ctx *)calloc(1, sizeof(struct tango_cache_ctx)); ctx->instance = instance; ctx->future = f; @@ -546,6 +565,13 @@ struct tango_cache_ctx *tango_cache_multi_delete_prepare(struct tango_cache_inst struct tango_cache_ctx *ctx; char md5[48]={0}, content_md5[48]; + if(instance->statistic.session_num >= instance->max_session_num) + { + instance->error_code = CACHE_OUTOF_SESSION; + instance->statistic.totaldrop_num += 1; + return NULL; + } + ctx = (struct tango_cache_ctx *)calloc(1, sizeof(struct tango_cache_ctx)); ctx->instance = instance; ctx->future = f; @@ -755,9 +781,12 @@ static int load_local_configure(struct tango_cache_instance *instance, const cha MESA_load_profile_uint_def(profile_path, section, "MAX_CONNECTION_PER_HOST", &intval, 0); instance->max_cnn_host = intval; + MESA_load_profile_uint_def(profile_path, section, "MAX_CURL_SESSION_NUM", &instance->max_session_num, 200); 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_uint_def(profile_path, section, "MAX_CURL_TRANSFER_TIMEOUT_S", &intval, 15); + instance->transfer_timeout = intval; 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); diff --git a/cache/src/tango_cache_client_in.h b/cache/src/tango_cache_client_in.h index bd82dbc..a9b7688 100644 --- a/cache/src/tango_cache_client_in.h +++ b/cache/src/tango_cache_client_in.h @@ -70,6 +70,8 @@ struct tango_cache_instance time_t relative_ttl; //缓存的相对有效期 u_int64_t cache_limit_size; long max_cnn_host; + long transfer_timeout;//传输总时间限制 + u_int32_t max_session_num; u_int32_t upload_block_size; //minio分段上传块的最小长度 enum CACHE_ERR_CODE error_code; @@ -154,8 +156,9 @@ void caculate_sha256(const char *data, unsigned long len, char *result, u_int32_ void easy_string_savedata(struct easy_string *estr, const char *data, size_t len); void easy_string_destroy(struct easy_string *estr); -void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx); +void tango_cache_ctx_destroy(struct tango_cache_ctx *ctx, bool callback=true); void tango_cache_set_fail_state(struct tango_cache_ctx *ctx, enum CACHE_ERR_CODE error_code); +const char *tango_cache_errcode2str(enum CACHE_ERR_CODE 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); diff --git a/cache/src/tango_cache_redis.cpp b/cache/src/tango_cache_redis.cpp index 198da85..e234011 100644 --- a/cache/src/tango_cache_redis.cpp +++ b/cache/src/tango_cache_redis.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "tango_cache_transfer.h" #include "tango_cache_tools.h" @@ -39,7 +39,7 @@ struct http_hdr_name g_http_hdr_name[HDR_CONTENT_NUM]= {"content-md5", "Content-MD5: "} }; -void redis_asyn_disconnect_cb(const struct redisAsyncContext *ac, int status) +static void redis_asyn_disconnect_cb(const struct redisAsyncContext *ac, int status) { struct tango_cache_instance *instance = (struct tango_cache_instance *)redisAsyncGetConnectionData(ac); @@ -54,7 +54,7 @@ void redis_asyn_disconnect_cb(const struct redisAsyncContext *ac, int status) instance->redis_connecting = CACHE_REDIS_DISCONNECTED; } -void redis_asyn_connect_cb(const struct redisAsyncContext *ac, int status) +static void redis_asyn_connect_cb(const struct redisAsyncContext *ac, int status) { struct tango_cache_instance *instance = (struct tango_cache_instance *)redisAsyncGetConnectionData(ac); @@ -85,7 +85,7 @@ int redis_asyn_connect_init(struct tango_cache_instance *instance) return 0; } -int parse_minio_events_json(struct tango_cache_ctx *ctx, const char *jcontent) +static 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; @@ -160,7 +160,7 @@ out_json: return ret; } -void redis_hget_command_cb(struct redisAsyncContext *ac, void *vreply, void *privdata) +static 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; diff --git a/cache/src/tango_cache_transfer.cpp b/cache/src/tango_cache_transfer.cpp index 87d870e..20dd2f6 100644 --- a/cache/src/tango_cache_transfer.cpp +++ b/cache/src/tango_cache_transfer.cpp @@ -127,6 +127,7 @@ static int http_put_bodypart_request_evbuf(struct tango_cache_ctx *ctx, bool ful curl_easy_setopt(ctx->curl, CURLOPT_PRIVATE, ctx); curl_easy_setopt(ctx->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(ctx->curl, CURLOPT_CONNECTTIMEOUT_MS, 500L); + curl_easy_setopt(ctx->curl, CURLOPT_TIMEOUT, ctx->instance->transfer_timeout); //测试发现有某链接接收卡住的情况 curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->headers); curl_easy_setopt(ctx->curl, CURLOPT_LOW_SPEED_TIME, 2L); curl_easy_setopt(ctx->curl, CURLOPT_LOW_SPEED_LIMIT, 100L); @@ -200,7 +201,7 @@ int curl_get_minio_uploadID(struct tango_cache_ctx *ctx) return 1; } -int cache_delete_minio_object(struct tango_cache_ctx *ctx) +int cache_delete_minio_object(struct tango_cache_ctx *ctx, bool call_back) { CURLMcode rc; char minio_url[256]; @@ -208,8 +209,9 @@ 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); //终结者 - return 0; + tango_cache_set_fail_state(ctx, CACHE_ERR_CURL); + tango_cache_ctx_destroy(ctx, call_back); //终结者 + return -1; } snprintf(minio_url, 256, "http://%s/%s/%s", ctx->hostaddr, ctx->instance->bucketname, ctx->object_key); @@ -330,9 +332,10 @@ bool cache_kick_upload_minio_multipart(struct tango_cache_ctx *ctx, size_t block return true; } -int http_put_complete_part_evbuf(struct tango_cache_ctx *ctx) +//callback直接失败是否调用回调函数,流式需要,完整一次性不需要 +static int http_put_complete_part_evbuf(struct tango_cache_ctx *ctx, bool callback) { - int ret=0; + int ret=-1; ctx->put.state = PUT_STATE_END; ctx->put.upload_length = evbuffer_get_length(ctx->put.evbuf); @@ -342,33 +345,30 @@ int http_put_complete_part_evbuf(struct tango_cache_ctx *ctx) if(ret <= 0) { tango_cache_set_fail_state(ctx, CACHE_ERR_CURL); - tango_cache_ctx_destroy(ctx); + tango_cache_ctx_destroy(ctx, callback); } } else { - tango_cache_ctx_destroy(ctx); + tango_cache_ctx_destroy(ctx, callback); } - return ret; } -int cache_kick_upload_minio_end(struct tango_cache_ctx *ctx) +void cache_kick_upload_minio_end(struct tango_cache_ctx *ctx) { - int ret = 0; - DBG_CACHE("state: %d, key: %s, curl %s NULL\n", ctx->put.state, ctx->object_key, (ctx->curl==NULL)?"is":"is not"); ctx->put.close_state = true;//仅设置状态,并非真正关闭;内部状态机轮转结束后再关闭 if(ctx->fail_state) { tango_cache_ctx_destroy(ctx); - return 0; + return; } switch(ctx->put.state) { case PUT_STATE_START: - ret = http_put_complete_part_evbuf(ctx); + http_put_complete_part_evbuf(ctx, true); break; case PUT_STATE_PART: @@ -387,20 +387,16 @@ int cache_kick_upload_minio_end(struct tango_cache_ctx *ctx) tango_cache_ctx_destroy(ctx); } } - else + else if(http_put_bodypart_request_evbuf(ctx, false) <= 0) { - ret = http_put_bodypart_request_evbuf(ctx, false); - if(ret <= 0) + tango_cache_set_fail_state(ctx, CACHE_ERR_CURL); + if(cache_cancel_upload_minio(ctx)) { - tango_cache_set_fail_state(ctx, CACHE_ERR_CURL); - if(cache_cancel_upload_minio(ctx)) - { - ctx->put.state = PUT_STATE_CANCEL; - } - else - { - tango_cache_ctx_destroy(ctx); - } + ctx->put.state = PUT_STATE_CANCEL; + } + else + { + tango_cache_ctx_destroy(ctx); } } } @@ -410,8 +406,6 @@ int cache_kick_upload_minio_end(struct tango_cache_ctx *ctx) case PUT_STATE_WAIT_START: //此时未获取到uploadId,所以无法触发上传 default: break; } - - return ret; } void tango_cache_curl_put_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code) @@ -496,7 +490,7 @@ void tango_cache_curl_put_done(struct tango_cache_ctx *ctx, CURLcode res, long r } } -int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEMORY_COPY_WAY way, const char *data, size_t size) +int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEMORY_COPY_WAY way, const char *data, size_t size, bool callback) { CURLMcode rc; char minio_url[256]; @@ -505,11 +499,9 @@ int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEM ctx->instance->error_code = CACHE_OK; if(NULL == (ctx->curl=curl_easy_init())) { - tango_cache_ctx_destroy(ctx); - if(way == PUT_MEM_FREE) - { - free((void *)data); - } + tango_cache_set_fail_state(ctx, CACHE_ERR_CURL); + tango_cache_ctx_destroy(ctx, callback); + if(way == PUT_MEM_FREE) free((void *)data); return -1; } ctx->put.state = PUT_STATE_END; @@ -524,6 +516,7 @@ int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEM curl_easy_setopt(ctx->curl, CURLOPT_PRIVATE, ctx); curl_easy_setopt(ctx->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(ctx->curl, CURLOPT_CONNECTTIMEOUT_MS, 500L); + curl_easy_setopt(ctx->curl, CURLOPT_TIMEOUT, ctx->instance->transfer_timeout); //测试发现有某链接接收卡住的情况 curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->headers); curl_easy_setopt(ctx->curl, CURLOPT_LOW_SPEED_TIME, 2L); curl_easy_setopt(ctx->curl, CURLOPT_LOW_SPEED_LIMIT, 100L); @@ -550,7 +543,7 @@ int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEM return 0; } -int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COPY_WAY way, struct evbuffer *evbuf) +int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COPY_WAY way, struct evbuffer *evbuf, bool callback) { size_t size; @@ -562,6 +555,8 @@ int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFF { if(evbuffer_add_buffer(ctx->put.evbuf, evbuf)) { + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); + tango_cache_ctx_destroy(ctx, callback); return -1; } } @@ -569,12 +564,14 @@ int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFF { if(evbuffer_add_buffer_reference(ctx->put.evbuf, evbuf)) { + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); + tango_cache_ctx_destroy(ctx, callback); return -1; } } ctx->instance->statistic.memory_used += size; - return http_put_complete_part_evbuf(ctx); + return http_put_complete_part_evbuf(ctx, callback); } void tango_cache_curl_del_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code) @@ -616,7 +613,7 @@ void tango_cache_curl_muldel_done(struct tango_cache_ctx *ctx, CURLcode res, lon tango_cache_ctx_destroy(ctx); } -int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx) +int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx, bool callback) { CURLMcode rc; char minio_url[256]; @@ -625,7 +622,8 @@ int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx) ctx->instance->error_code = CACHE_OK; if(NULL == (ctx->curl=curl_easy_init())) { - tango_cache_ctx_destroy(ctx); + tango_cache_set_fail_state(ctx, CACHE_OUTOF_MEMORY); + tango_cache_ctx_destroy(ctx, callback); return -1; } @@ -888,6 +886,7 @@ int tango_cache_fetch_start(struct tango_cache_ctx *ctx) curl_easy_setopt(ctx->curl, CURLOPT_PRIVATE, ctx); curl_easy_setopt(ctx->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(ctx->curl, CURLOPT_CONNECTTIMEOUT_MS, 500L); + curl_easy_setopt(ctx->curl, CURLOPT_TIMEOUT, ctx->instance->transfer_timeout); //测试发现有某链接接收卡住的情况 curl_easy_setopt(ctx->curl, CURLOPT_HEADERFUNCTION, curl_get_response_header_cb); curl_easy_setopt(ctx->curl, CURLOPT_HEADERDATA, ctx); //ctx->error="Operation too slow. Less than 1024 bytes/sec transferred the last 3 seconds" @@ -896,6 +895,6 @@ int tango_cache_fetch_start(struct tango_cache_ctx *ctx) rc = curl_multi_add_handle(ctx->instance->multi_hd, ctx->curl); assert(rc==CURLM_OK); - return 0; + return 1; } diff --git a/cache/src/tango_cache_transfer.h b/cache/src/tango_cache_transfer.h index 9c85eb5..c5db9d5 100644 --- a/cache/src/tango_cache_transfer.h +++ b/cache/src/tango_cache_transfer.h @@ -14,14 +14,14 @@ void tango_cache_curl_get_done(struct tango_cache_ctx *ctx, CURLcode res, long r void tango_cache_curl_del_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code); void tango_cache_curl_muldel_done(struct tango_cache_ctx *ctx, CURLcode res, long res_code); -int cache_delete_minio_object(struct tango_cache_ctx *ctx); -int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx); +int cache_delete_minio_object(struct tango_cache_ctx *ctx, bool call_back=false); +int tango_cache_multi_delete_start(struct tango_cache_ctx *ctx, bool callback=false); -int cache_kick_upload_minio_end(struct tango_cache_ctx *ctx); +void cache_kick_upload_minio_end(struct tango_cache_ctx *ctx); bool cache_kick_upload_minio_multipart(struct tango_cache_ctx *ctx, size_t block_len); -int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEMORY_COPY_WAY way, const char *data, size_t size); -int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COPY_WAY way, struct evbuffer *evbuf); +int tango_cache_upload_once_start_data(struct tango_cache_ctx *ctx, enum PUT_MEMORY_COPY_WAY way, const char *data, size_t size, bool call_back=false); +int tango_cache_upload_once_start_evbuf(struct tango_cache_ctx *ctx, enum EVBUFFER_COPY_WAY way, struct evbuffer *evbuf, bool call_back=false); int tango_cache_fetch_start(struct tango_cache_ctx *ctx); diff --git a/cache/test/lib/libhiredis.a b/cache/test/lib/libhiredis.a index 26434df401b497a7aaf36de4896ac86faaf8a9df..670ea58f661f76385172a6664ff604f269442b2f 100644 GIT binary patch delta 37385 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 HDr5d1I&xtc diff --git a/cache/test/tango_cache_test.c b/cache/test/tango_cache_test.c index c24ac41..560673c 100644 --- a/cache/test/tango_cache_test.c +++ b/cache/test/tango_cache_test.c @@ -76,6 +76,10 @@ void get_future_success(future_result_t* result, void * user) void get_future_failed(enum e_future_error err, const char * what, void * user) { + struct future_pdata *pdata = (struct future_pdata *)user; + future_destroy(pdata->future); + fclose(pdata->fp); + free(pdata); printf("GET fail: %s\n", what); } @@ -110,6 +114,10 @@ void head_future_success(future_result_t* result, void * user) void head_future_failed(enum e_future_error err, const char * what, void * user) { + struct future_pdata *pdata = (struct future_pdata *)user; + + future_destroy(pdata->future); + free(pdata); printf("HEAD fail: %s\n", what); } @@ -204,8 +212,6 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) struct future_pdata *pdata; struct tango_cache_ctx *ctx; - - pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); do { @@ -230,23 +236,30 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) if(!strcasecmp(p, "GET")) { sprintf(filename, "file_index_%u.bin", index++); + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->fp = fopen(filename, "w"); pdata->future = future_create(get_future_success, get_future_failed, pdata); - tango_cache_fetch_object(tango_instance, pdata->future, &getmeta); + if(tango_cache_fetch_object(tango_instance, pdata->future, &getmeta) < 0) + { + get_future_failed(FUTURE_ERROR_CANCEL, "", pdata); + } } else if(!strcasecmp(p, "HEAD")) { - sprintf(filename, "file_index_%u.bin", index++); - pdata->fp = fopen(filename, "w"); + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(head_future_success, head_future_failed, pdata); - tango_cache_head_object(tango_instance, pdata->future, &getmeta); + if(tango_cache_head_object(tango_instance, pdata->future, &getmeta) < 0) + { + head_future_failed(FUTURE_ERROR_CANCEL, "", pdata); + } } else if(!strcasecmp(p, "PUTONCE")) { size_t filelen; p = get_file_content(s, &filelen); + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(put_future_success, put_future_failed, pdata); tango_cache_upload_once_data(tango_instance, pdata->future, PUT_MEM_FREE, p, filelen, &putmeta, pdata->filename, 256); @@ -254,6 +267,7 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) else if(!strcasecmp(p, "PUTONCEEV")) { size_t readlen; + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(put_future_success, put_future_failed, pdata); struct evbuffer *evbuf = evbuffer_new(); char buffer[1024]; @@ -273,12 +287,14 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) } else if(!strcasecmp(p, "DEL")) { + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(del_future_success, del_future_failed, pdata); sprintf(pdata->filename, "%s", s); tango_cache_delete_object(tango_instance, pdata->future, s); } else if(!strcasecmp(p, "DELMUL")) //TODO { + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(del_future_success, del_future_failed, pdata); sprintf(pdata->filename, "%s", s); @@ -290,9 +306,15 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) } else { + pdata = (struct future_pdata *)malloc(sizeof(struct future_pdata)); pdata->future = future_create(put_future_success, put_future_failed, pdata); ctx = tango_cache_update_start(tango_instance, pdata->future, &putmeta); + if(ctx==NULL) + { + put_future_failed(FUTURE_ERROR_CANCEL, "NULL", pdata); + continue; + } tango_cache_get_object_path(ctx, pdata->filename, 256); FILE *fp = fopen(s, "r"); @@ -302,6 +324,7 @@ static void dummy_accept_callback(evutil_socket_t fd, short events, void *arg) assert(n>=0); tango_cache_update_frag_data(ctx, buffer, n); } + fclose(fp); tango_cache_update_end(ctx); } } diff --git a/vendor/hiredis-0.14.0-modified.zip b/vendor/hiredis-0.14.0.zip similarity index 75% rename from vendor/hiredis-0.14.0-modified.zip rename to vendor/hiredis-0.14.0.zip index 509f4205bf25a243cbd0e32bfa81097f87e2b6bc..06b0892a4cb20f7fde7f433b696a81e7a18af346 100644 GIT binary patch delta 17380 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
`dh*sGxKKfw3yfeFhQBGyfm83hwkBI&oETt2 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 o-woaamY=<{9 delta 17509 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 E58P$Ood5s;