1474 lines
34 KiB
C
1474 lines
34 KiB
C
/**
|
|
* Copyright (C) 2008 Happy Fish / YuQing
|
|
*
|
|
* FastDFS may be copied only under the terms of the GNU General
|
|
* Public License V3, which may be found in the FastDFS source kit.
|
|
* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
|
|
**/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include "fastcommon/sockopt.h"
|
|
#include "fastcommon/logger.h"
|
|
#include "fastcommon/hash.h"
|
|
#include "fastcommon/shared_func.h"
|
|
#include "fastcommon/ini_file_reader.h"
|
|
#include "fdht_types.h"
|
|
#include "fdht_proto.h"
|
|
#include "fdht_global.h"
|
|
#include "fdht_client.h"
|
|
|
|
GroupArray g_group_array = {NULL, 0};
|
|
bool g_keep_alive = false;
|
|
|
|
static void fdht_proxy_extra_deal(GroupArray *pGroupArray, bool *bKeepAlive)
|
|
{
|
|
int group_id;
|
|
ServerArray *pServerArray;
|
|
FDHTServerInfo **ppServer;
|
|
FDHTServerInfo **ppServerEnd;
|
|
|
|
if (!pGroupArray->use_proxy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
*bKeepAlive = true;
|
|
pGroupArray->server_count = 1;
|
|
memcpy(pGroupArray->servers, &pGroupArray->proxy_server, \
|
|
sizeof(FDHTServerInfo));
|
|
|
|
pServerArray = pGroupArray->groups;
|
|
for (group_id=0; group_id<pGroupArray->group_count; group_id++)
|
|
{
|
|
ppServerEnd = pServerArray->servers + pServerArray->count;
|
|
for (ppServer=pServerArray->servers; \
|
|
ppServer<ppServerEnd; ppServer++)
|
|
{
|
|
*ppServer = pGroupArray->servers;
|
|
}
|
|
|
|
pServerArray++;
|
|
}
|
|
}
|
|
|
|
int fdht_client_init(const char *filename)
|
|
{
|
|
char *pBasePath;
|
|
IniContext iniContext;
|
|
char szProxyPrompt[64];
|
|
int result;
|
|
|
|
memset(&iniContext, 0, sizeof(IniContext));
|
|
if ((result=iniLoadFromFile(filename, &iniContext)) != 0)
|
|
{
|
|
logError("load conf file \"%s\" fail, ret code: %d", \
|
|
filename, result);
|
|
return result;
|
|
}
|
|
|
|
//iniPrintItems(&iniContext);
|
|
|
|
while (1)
|
|
{
|
|
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
|
|
if (pBasePath == NULL)
|
|
{
|
|
logError("conf file \"%s\" must have item " \
|
|
"\"base_path\"!", filename);
|
|
result = ENOENT;
|
|
break;
|
|
}
|
|
|
|
snprintf(g_fdht_base_path, sizeof(g_fdht_base_path), "%s", pBasePath);
|
|
chopPath(g_fdht_base_path);
|
|
if (!fileExists(g_fdht_base_path))
|
|
{
|
|
logError("\"%s\" can't be accessed, error info: %s", \
|
|
g_fdht_base_path, STRERROR(errno));
|
|
result = errno != 0 ? errno : ENOENT;
|
|
break;
|
|
}
|
|
if (!isDir(g_fdht_base_path))
|
|
{
|
|
logError("\"%s\" is not a directory!", g_fdht_base_path);
|
|
result = ENOTDIR;
|
|
break;
|
|
}
|
|
|
|
g_fdht_connect_timeout = iniGetIntValue(NULL, "connect_timeout", \
|
|
&iniContext, DEFAULT_CONNECT_TIMEOUT);
|
|
if (g_fdht_connect_timeout <= 0)
|
|
{
|
|
g_fdht_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
|
}
|
|
|
|
g_fdht_network_timeout = iniGetIntValue(NULL, "network_timeout", \
|
|
&iniContext, DEFAULT_NETWORK_TIMEOUT);
|
|
if (g_fdht_network_timeout <= 0)
|
|
{
|
|
g_fdht_network_timeout = DEFAULT_NETWORK_TIMEOUT;
|
|
}
|
|
|
|
g_keep_alive = iniGetBoolValue(NULL, "keep_alive", \
|
|
&iniContext, false);
|
|
|
|
if ((result=fdht_load_groups(&iniContext, \
|
|
&g_group_array)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (g_group_array.use_proxy)
|
|
{
|
|
sprintf(szProxyPrompt, "proxy_addr=%s, proxy_port=%d, ",
|
|
g_group_array.proxy_server.ip_addr,
|
|
g_group_array.proxy_server.port);
|
|
}
|
|
else
|
|
{
|
|
*szProxyPrompt = '\0';
|
|
}
|
|
|
|
load_log_level(&iniContext);
|
|
|
|
logInfo("file: "__FILE__", line: %d, " \
|
|
"base_path=%s, " \
|
|
"connect_timeout=%ds, network_timeout=%ds, " \
|
|
"keep_alive=%d, use_proxy=%d, %s"\
|
|
"group_count=%d, server_count=%d", __LINE__, \
|
|
g_fdht_base_path, g_fdht_connect_timeout, \
|
|
g_fdht_network_timeout, g_keep_alive, \
|
|
g_group_array.use_proxy, szProxyPrompt, \
|
|
g_group_array.group_count, g_group_array.server_count);
|
|
|
|
fdht_proxy_extra_deal(&g_group_array, &g_keep_alive);
|
|
|
|
break;
|
|
}
|
|
|
|
iniFreeContext(&iniContext);
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_load_conf(const char *filename, GroupArray *pGroupArray, \
|
|
bool *bKeepAlive)
|
|
{
|
|
IniContext iniContext;
|
|
int result;
|
|
|
|
if ((result=iniLoadFromFile(filename, &iniContext)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"load conf file \"%s\" fail, " \
|
|
"ret code: %d", __LINE__, \
|
|
filename, result);
|
|
return result;
|
|
}
|
|
|
|
*bKeepAlive = iniGetBoolValue(NULL, "keep_alive", &iniContext, false);
|
|
if ((result=fdht_load_groups(&iniContext, pGroupArray)) != 0)
|
|
{
|
|
iniFreeContext(&iniContext);
|
|
return result;
|
|
}
|
|
|
|
fdht_proxy_extra_deal(pGroupArray, bKeepAlive);
|
|
|
|
iniFreeContext(&iniContext);
|
|
return 0;
|
|
}
|
|
|
|
void fdht_client_destroy()
|
|
{
|
|
fdht_free_group_array(&g_group_array);
|
|
}
|
|
|
|
#define get_readable_connection(pServerArray, bKeepAlive, hash_code, err_no) \
|
|
get_connection(pServerArray, bKeepAlive, hash_code, err_no)
|
|
|
|
#define get_writable_connection(pServerArray, bKeepAlive, hash_code, err_no) \
|
|
get_connection(pServerArray, bKeepAlive, hash_code, err_no)
|
|
|
|
static FDHTServerInfo *get_connection(ServerArray *pServerArray, \
|
|
const bool bKeepAlive, const int hash_code, int *err_no)
|
|
{
|
|
FDHTServerInfo **ppServer;
|
|
FDHTServerInfo **ppEnd;
|
|
int server_index;
|
|
int new_hash_code;
|
|
|
|
new_hash_code = (hash_code << 16) | (hash_code >> 16);
|
|
if (new_hash_code < 0)
|
|
{
|
|
new_hash_code &= 0x7FFFFFFF;
|
|
}
|
|
server_index = new_hash_code % pServerArray->count;
|
|
ppEnd = pServerArray->servers + pServerArray->count;
|
|
for (ppServer = pServerArray->servers + server_index; \
|
|
ppServer<ppEnd; ppServer++)
|
|
{
|
|
if ((*ppServer)->sock > 0) //already connected
|
|
{
|
|
return *ppServer;
|
|
}
|
|
|
|
if (fdht_connect_server_nb(*ppServer, \
|
|
g_fdht_connect_timeout) == 0)
|
|
{
|
|
if (bKeepAlive)
|
|
{
|
|
tcpsetnodelay((*ppServer)->sock, 3600);
|
|
}
|
|
return *ppServer;
|
|
}
|
|
}
|
|
|
|
ppEnd = pServerArray->servers + server_index;
|
|
for (ppServer = pServerArray->servers; ppServer<ppEnd; ppServer++)
|
|
{
|
|
if ((*ppServer)->sock > 0) //already connected
|
|
{
|
|
return *ppServer;
|
|
}
|
|
|
|
if (fdht_connect_server_nb(*ppServer, \
|
|
g_fdht_connect_timeout) == 0)
|
|
{
|
|
if (bKeepAlive)
|
|
{
|
|
tcpsetnodelay((*ppServer)->sock, 3600);
|
|
}
|
|
return *ppServer;
|
|
}
|
|
}
|
|
|
|
*err_no = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
#define CALC_KEY_HASH_CODE(pKeyInfo, hash_key, hash_key_len, key_hash_code) \
|
|
if (pKeyInfo->namespace_len > FDHT_MAX_NAMESPACE_LEN) \
|
|
{ \
|
|
fprintf(stderr, "namespace length: %d exceeds, " \
|
|
"max length: %d\n", \
|
|
pKeyInfo->namespace_len, FDHT_MAX_NAMESPACE_LEN); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
if (pKeyInfo->obj_id_len > FDHT_MAX_OBJECT_ID_LEN) \
|
|
{ \
|
|
fprintf(stderr, "object ID length: %d exceeds, " \
|
|
"max length: %d\n", \
|
|
pKeyInfo->obj_id_len, FDHT_MAX_OBJECT_ID_LEN); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
if (pKeyInfo->key_len > FDHT_MAX_SUB_KEY_LEN) \
|
|
{ \
|
|
fprintf(stderr, "key length: %d exceeds, max length: %d\n", \
|
|
pKeyInfo->key_len, FDHT_MAX_SUB_KEY_LEN); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
if (pKeyInfo->namespace_len == 0 && pKeyInfo->obj_id_len == 0) \
|
|
{ \
|
|
hash_key_len = pKeyInfo->key_len; \
|
|
memcpy(hash_key, pKeyInfo->szKey, pKeyInfo->key_len); \
|
|
} \
|
|
else if (pKeyInfo->namespace_len > 0 && pKeyInfo->obj_id_len > 0) \
|
|
{ \
|
|
hash_key_len = pKeyInfo->namespace_len+1+pKeyInfo->obj_id_len; \
|
|
memcpy(hash_key,pKeyInfo->szNameSpace,pKeyInfo->namespace_len);\
|
|
*(hash_key + pKeyInfo->namespace_len)=FDHT_FULL_KEY_SEPERATOR; \
|
|
memcpy(hash_key + pKeyInfo->namespace_len + 1, \
|
|
pKeyInfo->szObjectId, pKeyInfo->obj_id_len); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "invalid namespace length: %d and " \
|
|
"object ID length: %d\n", \
|
|
pKeyInfo->namespace_len, pKeyInfo->obj_id_len); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
key_hash_code = PJWHash(hash_key, hash_key_len); \
|
|
if (key_hash_code < 0) \
|
|
{ \
|
|
key_hash_code &= 0x7FFFFFFF; \
|
|
} \
|
|
|
|
|
|
#define CALC_OBJECT_HASH_CODE(pObjectInfo, hash_key, hash_key_len, key_hash_code) \
|
|
if (pObjectInfo->namespace_len <= 0 || pObjectInfo->obj_id_len <= 0) \
|
|
{ \
|
|
fprintf(stderr, "invalid namespace length: %d and " \
|
|
"object ID length: %d\n", \
|
|
pObjectInfo->namespace_len, pObjectInfo->obj_id_len); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
if (pObjectInfo->namespace_len > FDHT_MAX_NAMESPACE_LEN) \
|
|
{ \
|
|
fprintf(stderr, "namespace length: %d exceeds, " \
|
|
"max length: %d\n", \
|
|
pObjectInfo->namespace_len, FDHT_MAX_NAMESPACE_LEN); \
|
|
return EINVAL; \
|
|
} \
|
|
\
|
|
if (pObjectInfo->obj_id_len > FDHT_MAX_OBJECT_ID_LEN) \
|
|
{ \
|
|
fprintf(stderr, "object ID length: %d exceeds, " \
|
|
"max length: %d\n", \
|
|
pObjectInfo->obj_id_len, FDHT_MAX_OBJECT_ID_LEN); \
|
|
return EINVAL; \
|
|
} \
|
|
hash_key_len = pObjectInfo->namespace_len+1+pObjectInfo->obj_id_len; \
|
|
memcpy(hash_key, pObjectInfo->szNameSpace, pObjectInfo->namespace_len);\
|
|
*(hash_key + pObjectInfo->namespace_len) = FDHT_FULL_KEY_SEPERATOR; \
|
|
memcpy(hash_key + pObjectInfo->namespace_len + 1, \
|
|
pObjectInfo->szObjectId, pObjectInfo->obj_id_len); \
|
|
\
|
|
key_hash_code = PJWHash(hash_key, hash_key_len); \
|
|
if (key_hash_code < 0) \
|
|
{ \
|
|
key_hash_code &= 0x7FFFFFFF; \
|
|
} \
|
|
|
|
|
|
/**
|
|
* request body format:
|
|
* namespace_len: 4 bytes big endian integer
|
|
* namespace: can be emtpy
|
|
* obj_id_len: 4 bytes big endian integer
|
|
* object_id: the object id (can be empty)
|
|
* key_len: 4 bytes big endian integer
|
|
* key: key name
|
|
* response body format:
|
|
* value_len: 4 bytes big endian integer
|
|
* value: value buff
|
|
*/
|
|
int fdht_get_ex1(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTKeyInfo *pKeyInfo, const time_t expires, \
|
|
char **ppValue, int *value_len, MallocFunc malloc_func)
|
|
{
|
|
int result;
|
|
FDHTProtoHeader *pHeader;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + 16];
|
|
int in_bytes;
|
|
int vlen;
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
char *p;
|
|
|
|
CALC_KEY_HASH_CODE(pKeyInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
//printf("get group_id=%d\n", group_id);
|
|
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_readable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
pHeader = (FDHTProtoHeader *)buff;
|
|
|
|
pHeader->cmd = FDHT_PROTO_CMD_GET;
|
|
pHeader->keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), pHeader->timestamp);
|
|
int2buff((int)expires, pHeader->expires);
|
|
int2buff(key_hash_code, pHeader->key_hash_code);
|
|
int2buff(12 + pKeyInfo->namespace_len + pKeyInfo->obj_id_len + \
|
|
pKeyInfo->key_len, pHeader->pkg_len);
|
|
|
|
do
|
|
{
|
|
p = buff + sizeof(FDHTProtoHeader);
|
|
PACK_BODY_UNTIL_KEY(pKeyInfo, p)
|
|
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
|
|
g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (in_bytes < 4)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d < 4", \
|
|
pServer->ip_addr, pServer->port, in_bytes);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, buff, \
|
|
4, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, \
|
|
pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
vlen = buff2int(buff);
|
|
if (vlen != in_bytes - 4)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d " \
|
|
"is not correct, %d != %d", pServer->ip_addr, \
|
|
pServer->port, in_bytes, vlen, in_bytes - 4);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (*ppValue != NULL)
|
|
{
|
|
if (vlen >= *value_len)
|
|
{
|
|
*value_len = 0;
|
|
result = ENOSPC;
|
|
break;
|
|
}
|
|
|
|
*value_len = vlen;
|
|
}
|
|
else
|
|
{
|
|
*value_len = vlen;
|
|
*ppValue = (char *)malloc_func((*value_len + 1));
|
|
if (*ppValue == NULL)
|
|
{
|
|
*value_len = 0;
|
|
logError("malloc %d bytes fail, " \
|
|
"errno: %d, error info: %s", \
|
|
*value_len + 1, errno, STRERROR(errno));
|
|
result = errno != 0 ? errno : ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, *ppValue, \
|
|
*value_len, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, \
|
|
pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
*(*ppValue + *value_len) = '\0';
|
|
} while(0);
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_batch_set_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
|
|
const int key_count, const time_t expires, int *success_count)
|
|
{
|
|
int result;
|
|
FDHTProtoHeader *pHeader;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + \
|
|
(8 + FDHT_MAX_SUB_KEY_LEN) * FDHT_MAX_KEY_COUNT_PER_REQ + \
|
|
32 * 1024];
|
|
char *pBuff;
|
|
int in_bytes;
|
|
int total_key_len;
|
|
int total_value_len;
|
|
int pkg_total_len;
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
FDHTKeyValuePair *pKeyValuePair;
|
|
FDHTKeyValuePair *pKeyValueEnd;
|
|
char *p;
|
|
|
|
*success_count = 0;
|
|
if (key_count <= 0 || key_count > FDHT_MAX_KEY_COUNT_PER_REQ)
|
|
{
|
|
logError("invalid key_count: %d", key_count);
|
|
return EINVAL;
|
|
}
|
|
|
|
CALC_OBJECT_HASH_CODE(pObjectInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_writable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
total_key_len = 0;
|
|
total_value_len = 0;
|
|
pKeyValueEnd = key_list + key_count;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; pKeyValuePair++)
|
|
{
|
|
total_key_len += pKeyValuePair->key_len;
|
|
total_value_len += pKeyValuePair->value_len;
|
|
}
|
|
pkg_total_len = sizeof(FDHTProtoHeader) + 12 + pObjectInfo->namespace_len + \
|
|
pObjectInfo->obj_id_len + 8 * key_count + \
|
|
total_key_len + total_value_len;
|
|
|
|
if (pkg_total_len <= sizeof(buff))
|
|
{
|
|
pBuff = buff;
|
|
}
|
|
else
|
|
{
|
|
pBuff = (char *)malloc(pkg_total_len);
|
|
if (pBuff == NULL)
|
|
{
|
|
result = errno != 0 ? errno : ENOMEM;
|
|
logError("malloc %d bytes fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pkg_total_len, result, STRERROR(result));
|
|
return result;
|
|
}
|
|
}
|
|
|
|
memset(pBuff, 0, pkg_total_len);
|
|
pHeader = (FDHTProtoHeader *)pBuff;
|
|
|
|
pHeader->cmd = FDHT_PROTO_CMD_BATCH_SET;
|
|
pHeader->keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), pHeader->timestamp);
|
|
int2buff((int)expires, pHeader->expires);
|
|
int2buff(key_hash_code, pHeader->key_hash_code);
|
|
|
|
p = pBuff + sizeof(FDHTProtoHeader);
|
|
PACK_BODY_OBJECT(pObjectInfo, p)
|
|
int2buff(key_count, p);
|
|
p += 4;
|
|
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; pKeyValuePair++)
|
|
{
|
|
int2buff(pKeyValuePair->key_len, p);
|
|
memcpy(p + 4, pKeyValuePair->szKey, pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
|
|
int2buff(pKeyValuePair->value_len, p);
|
|
memcpy(p + 4, pKeyValuePair->pValue, pKeyValuePair->value_len);
|
|
p += 4 + pKeyValuePair->value_len;
|
|
}
|
|
|
|
do
|
|
{
|
|
int2buff(pkg_total_len - sizeof(FDHTProtoHeader), pHeader->pkg_len);
|
|
if ((result=tcpsenddata_nb(pServer->sock, pBuff, pkg_total_len, \
|
|
g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (in_bytes != 8 + 5 * key_count + total_key_len)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d != %d", \
|
|
pServer->ip_addr, pServer->port, in_bytes, \
|
|
8 + 5 * key_count + total_key_len);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, pBuff, \
|
|
in_bytes, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if (buff2int(pBuff) != key_count)
|
|
{
|
|
result = EINVAL;
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, invalid key_count: %d, " \
|
|
"expect key count: %d", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
buff2int(pBuff), key_count);
|
|
break;
|
|
}
|
|
|
|
*success_count = buff2int(pBuff + 4);
|
|
p = pBuff + 8;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; \
|
|
pKeyValuePair++)
|
|
{
|
|
pKeyValuePair->key_len = buff2int(p);
|
|
|
|
memcpy(pKeyValuePair->szKey, p + 4, \
|
|
pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
pKeyValuePair->status = *p++;
|
|
}
|
|
} while (0);
|
|
|
|
if (pBuff != buff)
|
|
{
|
|
free(pBuff);
|
|
}
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_batch_delete_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
|
|
const int key_count, int *success_count)
|
|
{
|
|
int result;
|
|
FDHTProtoHeader *pHeader;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + 8 + \
|
|
(5 + FDHT_MAX_SUB_KEY_LEN) * FDHT_MAX_KEY_COUNT_PER_REQ];
|
|
int in_bytes;
|
|
int total_key_len;
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
FDHTKeyValuePair *pKeyValuePair;
|
|
FDHTKeyValuePair *pKeyValueEnd;
|
|
char *p;
|
|
|
|
*success_count = 0;
|
|
if (key_count <= 0 || key_count > FDHT_MAX_KEY_COUNT_PER_REQ)
|
|
{
|
|
logError("invalid key_count: %d", key_count);
|
|
return EINVAL;
|
|
}
|
|
|
|
CALC_OBJECT_HASH_CODE(pObjectInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_readable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
pHeader = (FDHTProtoHeader *)buff;
|
|
|
|
pHeader->cmd = FDHT_PROTO_CMD_BATCH_DEL;
|
|
pHeader->keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), pHeader->timestamp);
|
|
int2buff(key_hash_code, pHeader->key_hash_code);
|
|
|
|
p = buff + sizeof(FDHTProtoHeader);
|
|
PACK_BODY_OBJECT(pObjectInfo, p)
|
|
int2buff(key_count, p);
|
|
p += 4;
|
|
|
|
total_key_len = 0;
|
|
pKeyValueEnd = key_list + key_count;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; pKeyValuePair++)
|
|
{
|
|
int2buff(pKeyValuePair->key_len, p);
|
|
memcpy(p + 4, pKeyValuePair->szKey, pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
|
|
total_key_len += pKeyValuePair->key_len;
|
|
}
|
|
|
|
do
|
|
{
|
|
int2buff((p - buff) - sizeof(FDHTProtoHeader), pHeader->pkg_len);
|
|
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
|
|
g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (in_bytes != 8 + 5 * key_count + total_key_len)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d != %d", \
|
|
pServer->ip_addr, pServer->port, in_bytes, \
|
|
8 + 5 * key_count + total_key_len);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, buff, \
|
|
in_bytes, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if (buff2int(buff) != key_count)
|
|
{
|
|
result = EINVAL;
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, invalid key_count: %d, " \
|
|
"expect key count: %d", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
buff2int(buff), key_count);
|
|
break;
|
|
}
|
|
|
|
*success_count = buff2int(buff + 4);
|
|
p = buff + 8;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; \
|
|
pKeyValuePair++)
|
|
{
|
|
pKeyValuePair->key_len = buff2int(p);
|
|
|
|
memcpy(pKeyValuePair->szKey, p + 4, \
|
|
pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
pKeyValuePair->status = *p++;
|
|
}
|
|
} while (0);
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_batch_get_ex1(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTObjectInfo *pObjectInfo, FDHTKeyValuePair *key_list, \
|
|
const int key_count, const time_t expires, \
|
|
MallocFunc malloc_func, int *success_count)
|
|
{
|
|
int result;
|
|
FDHTProtoHeader *pHeader;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
char buff[sizeof(FDHTProtoHeader) + FDHT_MAX_FULL_KEY_LEN + \
|
|
(4 + FDHT_MAX_SUB_KEY_LEN) * FDHT_MAX_KEY_COUNT_PER_REQ + \
|
|
32 * 1024];
|
|
int in_bytes;
|
|
int value_len;
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
char *pInBuff;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
FDHTKeyValuePair *pKeyValuePair;
|
|
FDHTKeyValuePair *pKeyValueEnd;
|
|
char *p;
|
|
|
|
*success_count = 0;
|
|
if (key_count <= 0 || key_count > FDHT_MAX_KEY_COUNT_PER_REQ)
|
|
{
|
|
logError("invalid key_count: %d", key_count);
|
|
return EINVAL;
|
|
}
|
|
|
|
CALC_OBJECT_HASH_CODE(pObjectInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_readable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
pHeader = (FDHTProtoHeader *)buff;
|
|
|
|
pHeader->cmd = FDHT_PROTO_CMD_BATCH_GET;
|
|
pHeader->keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), pHeader->timestamp);
|
|
int2buff((int)expires, pHeader->expires);
|
|
int2buff(key_hash_code, pHeader->key_hash_code);
|
|
|
|
p = buff + sizeof(FDHTProtoHeader);
|
|
PACK_BODY_OBJECT(pObjectInfo, p)
|
|
int2buff(key_count, p);
|
|
p += 4;
|
|
|
|
pKeyValueEnd = key_list + key_count;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; pKeyValuePair++)
|
|
{
|
|
int2buff(pKeyValuePair->key_len, p);
|
|
memcpy(p + 4, pKeyValuePair->szKey, pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
}
|
|
|
|
pInBuff = buff;
|
|
do
|
|
{
|
|
int2buff((p - buff) - sizeof(FDHTProtoHeader), pHeader->pkg_len);
|
|
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
|
|
g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (in_bytes < 17)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d < 17", \
|
|
pServer->ip_addr, pServer->port, in_bytes);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (in_bytes > sizeof(buff))
|
|
{
|
|
pInBuff = (char *)malloc(in_bytes);
|
|
if (pInBuff == NULL)
|
|
{
|
|
result = errno != 0 ? errno : ENOMEM;
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"malloc %d bytes fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, in_bytes, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, pInBuff, \
|
|
in_bytes, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if (buff2int(pInBuff) != key_count)
|
|
{
|
|
result = EINVAL;
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, invalid key_count: %d, " \
|
|
"expect key count: %d", \
|
|
__LINE__, pServer->ip_addr, pServer->port, \
|
|
buff2int(pInBuff), key_count);
|
|
break;
|
|
}
|
|
|
|
*success_count = buff2int(pInBuff + 4);
|
|
p = pInBuff + 8;
|
|
for (pKeyValuePair=key_list; pKeyValuePair<pKeyValueEnd; \
|
|
pKeyValuePair++)
|
|
{
|
|
pKeyValuePair->key_len = buff2int(p);
|
|
|
|
memcpy(pKeyValuePair->szKey, p + 4, \
|
|
pKeyValuePair->key_len);
|
|
p += 4 + pKeyValuePair->key_len;
|
|
pKeyValuePair->status = *p++;
|
|
if (pKeyValuePair->status != 0)
|
|
{
|
|
pKeyValuePair->value_len = 0;
|
|
continue;
|
|
}
|
|
|
|
value_len = buff2int(p);
|
|
p += 4;
|
|
if (pKeyValuePair->pValue != NULL)
|
|
{
|
|
if (value_len >= pKeyValuePair->value_len)
|
|
{
|
|
*(pKeyValuePair->pValue) = '\0';
|
|
pKeyValuePair->value_len = 0;
|
|
pKeyValuePair->status = ENOSPC;
|
|
}
|
|
else
|
|
{
|
|
pKeyValuePair->value_len = value_len;
|
|
memcpy(pKeyValuePair->pValue, p, \
|
|
value_len);
|
|
*(pKeyValuePair->pValue+value_len)='\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pKeyValuePair->pValue = (char *)malloc_func( \
|
|
value_len + 1);
|
|
if (pKeyValuePair->pValue == NULL)
|
|
{
|
|
pKeyValuePair->value_len = 0;
|
|
pKeyValuePair->status = errno != 0 ? \
|
|
errno : ENOMEM;
|
|
logError("malloc %d bytes fail, " \
|
|
"errno: %d, error info: %s", \
|
|
value_len+1, errno, \
|
|
STRERROR(errno));
|
|
}
|
|
else
|
|
{
|
|
pKeyValuePair->value_len = value_len;
|
|
memcpy(pKeyValuePair->pValue, p, \
|
|
value_len);
|
|
*(pKeyValuePair->pValue+value_len)='\0';
|
|
}
|
|
}
|
|
|
|
p += value_len;
|
|
}
|
|
|
|
if (in_bytes != p - pInBuff)
|
|
{
|
|
*success_count = 0;
|
|
logError("server %s:%u reponse bytes: %d != %d", \
|
|
pServer->ip_addr, pServer->port, \
|
|
in_bytes, (int)(p - pInBuff));
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
} while (0);
|
|
|
|
if (pInBuff != buff)
|
|
{
|
|
free(pInBuff);
|
|
}
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_set_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTKeyInfo *pKeyInfo, const time_t expires, \
|
|
const char *pValue, const int value_len)
|
|
{
|
|
int result;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
|
|
CALC_KEY_HASH_CODE(pKeyInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_writable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//printf("key_hash_code=%d, group_id=%d\n", key_hash_code, group_id);
|
|
|
|
//printf("set group_id=%d\n", group_id);
|
|
result = fdht_client_set(pServer, bKeepAlive, time(NULL), expires, \
|
|
FDHT_PROTO_CMD_SET, key_hash_code, \
|
|
pKeyInfo, pValue, value_len);
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* request body format:
|
|
* namespace_len: 4 bytes big endian integer
|
|
* namespace: can be emtpy
|
|
* obj_id_len: 4 bytes big endian integer
|
|
* object_id: the object id (can be empty)
|
|
* key_len: 4 bytes big endian integer
|
|
* key: key name
|
|
* incr 4 bytes big endian integer
|
|
* response body format:
|
|
* value_len: 4 bytes big endian integer
|
|
* value : value_len bytes
|
|
*/
|
|
int fdht_inc_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTKeyInfo *pKeyInfo, const time_t expires, \
|
|
const int increase, char *pValue, int *value_len)
|
|
{
|
|
int result;
|
|
FDHTProtoHeader *pHeader;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
char buff[FDHT_MAX_FULL_KEY_LEN + 32];
|
|
char *in_buff;
|
|
int in_bytes;
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
char *p;
|
|
|
|
CALC_KEY_HASH_CODE(pKeyInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_writable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code, &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//printf("inc group_id=%d\n", group_id);
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
pHeader = (FDHTProtoHeader *)buff;
|
|
|
|
pHeader->cmd = FDHT_PROTO_CMD_INC;
|
|
pHeader->keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), pHeader->timestamp);
|
|
int2buff((int)expires, pHeader->expires);
|
|
int2buff(key_hash_code, pHeader->key_hash_code);
|
|
int2buff(16 + pKeyInfo->namespace_len + pKeyInfo->obj_id_len + \
|
|
pKeyInfo->key_len, pHeader->pkg_len);
|
|
|
|
while (1)
|
|
{
|
|
p = buff + sizeof(FDHTProtoHeader);
|
|
PACK_BODY_UNTIL_KEY(pKeyInfo, p)
|
|
int2buff(increase, p);
|
|
p += 4;
|
|
if ((result=tcpsenddata_nb(pServer->sock, buff, p - buff, \
|
|
g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
in_buff = buff;
|
|
if ((result=fdht_recv_response(pServer, &in_buff, \
|
|
sizeof(buff), &in_bytes)) != 0)
|
|
{
|
|
logError("recv data from server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if (in_bytes < 4)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d < 4!", \
|
|
pServer->ip_addr, pServer->port, in_bytes);
|
|
result = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (in_bytes - 4 >= *value_len)
|
|
{
|
|
*value_len = 0;
|
|
result = ENOSPC;
|
|
break;
|
|
}
|
|
|
|
*value_len = in_bytes - 4;
|
|
memcpy(pValue, in_buff + 4, *value_len);
|
|
*(pValue + (*value_len)) = '\0';
|
|
break;
|
|
}
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_delete_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
FDHTKeyInfo *pKeyInfo)
|
|
{
|
|
int result;
|
|
char hash_key[FDHT_MAX_FULL_KEY_LEN + 1];
|
|
int group_id;
|
|
int hash_key_len;
|
|
int key_hash_code;
|
|
int i;
|
|
ServerArray *pGroup;
|
|
FDHTServerInfo *pServer;
|
|
|
|
CALC_KEY_HASH_CODE(pKeyInfo, hash_key, hash_key_len, key_hash_code)
|
|
group_id = ((unsigned int)key_hash_code) % pGroupArray->group_count;
|
|
pGroup = pGroupArray->groups + group_id;
|
|
for (i=0; i<=pGroup->count; i++)
|
|
{
|
|
pServer = get_writable_connection(pGroup, bKeepAlive, \
|
|
key_hash_code , &result);
|
|
if (pServer == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//printf("del group_id=%d\n", group_id);
|
|
result = fdht_client_delete(pServer, bKeepAlive, time(NULL), \
|
|
FDHT_PROTO_CMD_DEL, key_hash_code, pKeyInfo);
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int fdht_connect_all_servers(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
int *success_count, int *fail_count)
|
|
{
|
|
FDHTServerInfo *pServerInfo;
|
|
FDHTServerInfo *pServerEnd;
|
|
int conn_result;
|
|
int result;
|
|
|
|
*success_count = 0;
|
|
*fail_count = 0;
|
|
if (pGroupArray->servers == NULL)
|
|
{
|
|
return ENOENT;
|
|
}
|
|
|
|
result = 0;
|
|
|
|
pServerEnd = pGroupArray->servers + pGroupArray->server_count;
|
|
for (pServerInfo=pGroupArray->servers; \
|
|
pServerInfo<pServerEnd; pServerInfo++)
|
|
{
|
|
if ((conn_result=fdht_connect_server_nb(pServerInfo, \
|
|
g_fdht_connect_timeout)) != 0)
|
|
{
|
|
result = conn_result;
|
|
(*fail_count)++;
|
|
}
|
|
else //connect success
|
|
{
|
|
(*success_count)++;
|
|
if (bKeepAlive || pGroupArray->use_proxy)
|
|
{
|
|
tcpsetnodelay(pServerInfo->sock, 3600);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result != 0)
|
|
{
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return *success_count > 0 ? 0: ENOENT;
|
|
}
|
|
}
|
|
|
|
void fdht_disconnect_all_servers(GroupArray *pGroupArray)
|
|
{
|
|
FDHTServerInfo *pServerInfo;
|
|
FDHTServerInfo *pServerEnd;
|
|
|
|
if (pGroupArray->servers != NULL)
|
|
{
|
|
pServerEnd = pGroupArray->servers + pGroupArray->server_count;
|
|
for (pServerInfo=pGroupArray->servers; \
|
|
pServerInfo<pServerEnd; pServerInfo++)
|
|
{
|
|
if (pServerInfo->sock >= 0)
|
|
{
|
|
if (!pGroupArray->use_proxy)
|
|
{
|
|
fdht_quit(pServerInfo);
|
|
}
|
|
close(pServerInfo->sock);
|
|
pServerInfo->sock = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int fdht_stat_ex(GroupArray *pGroupArray, const bool bKeepAlive, \
|
|
const int server_index, char *buff, const int size)
|
|
{
|
|
int result;
|
|
int in_bytes;
|
|
int i;
|
|
FDHTProtoHeader header;
|
|
FDHTServerInfo *pServer;
|
|
|
|
memset(buff, 0, size);
|
|
if (server_index < 0 || server_index > pGroupArray->server_count)
|
|
{
|
|
logError("invalid servier_index: %d", server_index);
|
|
return EINVAL;
|
|
}
|
|
|
|
pServer = pGroupArray->servers + server_index;
|
|
for (i=0; i<2; i++)
|
|
{
|
|
if ((result=fdht_connect_server_nb(pServer, \
|
|
g_fdht_connect_timeout)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
tcpsetnodelay(pServer->sock, 3600);
|
|
}
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
header.cmd = FDHT_PROTO_CMD_STAT;
|
|
header.keep_alive = bKeepAlive;
|
|
int2buff((int)time(NULL), header.timestamp);
|
|
|
|
do
|
|
{
|
|
if ((result=tcpsenddata_nb(pServer->sock, &header, \
|
|
sizeof(header), g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("send data to server %s:%u fail, " \
|
|
"errno: %d, error info: %s", \
|
|
pServer->ip_addr, pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
if ((result=fdht_recv_header(pServer, &in_bytes)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (in_bytes >= size)
|
|
{
|
|
logError("server %s:%u reponse bytes: %d >= " \
|
|
"buff size: %d", pServer->ip_addr, \
|
|
pServer->port, in_bytes, size);
|
|
result = ENOSPC;
|
|
break;
|
|
}
|
|
|
|
if ((result=tcprecvdata_nb(pServer->sock, buff, \
|
|
in_bytes, g_fdht_network_timeout)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"server: %s:%u, recv data fail, " \
|
|
"errno: %d, error info: %s", \
|
|
__LINE__, pServer->ip_addr, \
|
|
pServer->port, \
|
|
result, STRERROR(result));
|
|
break;
|
|
}
|
|
} while (0);
|
|
|
|
if (bKeepAlive)
|
|
{
|
|
if (result >= ENETDOWN) //network error
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
if (result == ENOTCONN)
|
|
{
|
|
continue; //retry
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fdht_disconnect_server(pServer);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|