提交 051af216 编写于 作者: weixin_48148422's avatar weixin_48148422

tbase-1422: free resource

上级 f2eac06a
...@@ -465,6 +465,12 @@ void tscDestroyResPointerInfo(SSqlRes *pRes); ...@@ -465,6 +465,12 @@ void tscDestroyResPointerInfo(SSqlRes *pRes);
void tscFreeSqlCmdData(SSqlCmd *pCmd); void tscFreeSqlCmdData(SSqlCmd *pCmd);
/**
* free query result of the sql object
* @param pObj
*/
void tscFreeSqlResult(SSqlObj* pSql);
/** /**
* only free part of resources allocated during query. * only free part of resources allocated during query.
* Note: this function is multi-thread safe. * Note: this function is multi-thread safe.
......
...@@ -694,7 +694,7 @@ int taos_select_db(TAOS *taos, const char *db) { ...@@ -694,7 +694,7 @@ int taos_select_db(TAOS *taos, const char *db) {
return taos_query(taos, sql); return taos_query(taos, sql);
} }
void taos_free_result(TAOS_RES *res) { void taos_free_result_imp(TAOS_RES* res, int keepCmd) {
if (res == NULL) return; if (res == NULL) return;
SSqlObj *pSql = (SSqlObj *)res; SSqlObj *pSql = (SSqlObj *)res;
...@@ -712,6 +712,8 @@ void taos_free_result(TAOS_RES *res) { ...@@ -712,6 +712,8 @@ void taos_free_result(TAOS_RES *res) {
pSql->thandle = NULL; pSql->thandle = NULL;
tscFreeSqlObj(pSql); tscFreeSqlObj(pSql);
tscTrace("%p Async SqlObj is freed by app", pSql); tscTrace("%p Async SqlObj is freed by app", pSql);
} else if (keepCmd) {
tscFreeSqlResult(pSql);
} else { } else {
tscFreeSqlObjPartial(pSql); tscFreeSqlObjPartial(pSql);
} }
...@@ -761,8 +763,13 @@ void taos_free_result(TAOS_RES *res) { ...@@ -761,8 +763,13 @@ void taos_free_result(TAOS_RES *res) {
* Then this object will be reused and no free operation is required. * Then this object will be reused and no free operation is required.
*/ */
pSql->thandle = NULL; pSql->thandle = NULL;
tscFreeSqlObjPartial(pSql); if (keepCmd) {
tscTrace("%p sql result is freed by app", pSql); tscFreeSqlResult(pSql);
tscTrace("%p sql result is freed by app while sql command is kept", pSql);
} else {
tscFreeSqlObjPartial(pSql);
tscTrace("%p sql result is freed by app", pSql);
}
} }
} else { } else {
// if no free resource msg is sent to vnode, we free this object immediately. // if no free resource msg is sent to vnode, we free this object immediately.
...@@ -772,6 +779,9 @@ void taos_free_result(TAOS_RES *res) { ...@@ -772,6 +779,9 @@ void taos_free_result(TAOS_RES *res) {
assert(pRes->numOfRows == 0 || (pCmd->command > TSDB_SQL_LOCAL)); assert(pRes->numOfRows == 0 || (pCmd->command > TSDB_SQL_LOCAL));
tscFreeSqlObj(pSql); tscFreeSqlObj(pSql);
tscTrace("%p Async sql result is freed by app", pSql); tscTrace("%p Async sql result is freed by app", pSql);
} else if (keepCmd) {
tscFreeSqlResult(pSql);
tscTrace("%p sql result is freed while sql command is kept", pSql);
} else { } else {
tscFreeSqlObjPartial(pSql); tscFreeSqlObjPartial(pSql);
tscTrace("%p sql result is freed", pSql); tscTrace("%p sql result is freed", pSql);
...@@ -779,6 +789,10 @@ void taos_free_result(TAOS_RES *res) { ...@@ -779,6 +789,10 @@ void taos_free_result(TAOS_RES *res) {
} }
} }
void taos_free_result(TAOS_RES *res) {
taos_free_result_imp(res, 0);
}
int taos_errno(TAOS *taos) { int taos_errno(TAOS *taos) {
STscObj *pObj = (STscObj *)taos; STscObj *pObj = (STscObj *)taos;
int code; int code;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "ttimer.h" #include "ttimer.h"
#include "tutil.h" #include "tutil.h"
#include "tscUtil.h" #include "tscUtil.h"
#include "tcache.h"
typedef struct SSubscriptionProgress { typedef struct SSubscriptionProgress {
int64_t uid; int64_t uid;
...@@ -82,7 +83,7 @@ void tscUpdateSubscriptionProgress(void* sub, int64_t uid, TSKEY ts) { ...@@ -82,7 +83,7 @@ void tscUpdateSubscriptionProgress(void* sub, int64_t uid, TSKEY ts) {
else if (p->uid < uid) else if (p->uid < uid)
s = m + 1; s = m + 1;
else { else {
if (ts >= p->key) p->key = ts + 1; if (ts >= p->key) p->key = ts;
break; break;
} }
} }
...@@ -148,25 +149,27 @@ static void tscProcessSubscriptionTimer(void *handle, void *tmrId) { ...@@ -148,25 +149,27 @@ static void tscProcessSubscriptionTimer(void *handle, void *tmrId) {
TAOS_RES* res = taos_consume(pSub); TAOS_RES* res = taos_consume(pSub);
if (res != NULL) { if (res != NULL) {
pSub->fp(pSub, res, pSub->param, 0); pSub->fp(pSub, res, pSub->param, 0);
// TODO: memory leak
} }
taosTmrReset(tscProcessSubscriptionTimer, pSub->interval, pSub, tscTmr, &pSub->pTimer); taosTmrReset(tscProcessSubscriptionTimer, pSub->interval, pSub, tscTmr, &pSub->pTimer);
} }
bool tscUpdateSubscription(STscObj* pObj, SSub* pSub) { int tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
int code = (uint8_t)tsParseSql(pSub->pSql, pObj->acctId, pObj->db, false); int code = (uint8_t)tsParseSql(pSub->pSql, pObj->acctId, pObj->db, false);
if (code != TSDB_CODE_SUCCESS) { if (code != TSDB_CODE_SUCCESS) {
taos_unsubscribe(pSub); tscError("failed to parse sql statement: %s", pSub->topic);
return false; return 0;
} }
int numOfMeters = 0; int numOfMeters = 0;
SSubscriptionProgress* progress = NULL; SSubscriptionProgress* progress = NULL;
// ??? if there's more than one vnode
SSqlCmd* pCmd = &pSub->pSql->cmd; SSqlCmd* pCmd = &pSub->pSql->cmd;
if (pCmd->command != TSDB_SQL_SELECT) {
tscError("only 'select' statement is allowed in subscription: %s", pSub->topic);
return 0;
}
SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, 0); SMeterMetaInfo *pMeterMetaInfo = tscGetMeterMetaInfo(pCmd, 0);
if (UTIL_METER_IS_NOMRAL_METER(pMeterMetaInfo)) { if (UTIL_METER_IS_NOMRAL_METER(pMeterMetaInfo)) {
...@@ -177,14 +180,20 @@ bool tscUpdateSubscription(STscObj* pObj, SSub* pSub) { ...@@ -177,14 +180,20 @@ bool tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
progress[0].key = tscGetSubscriptionProgress(pSub, uid); progress[0].key = tscGetSubscriptionProgress(pSub, uid);
} else { } else {
SMetricMeta* pMetricMeta = pMeterMetaInfo->pMetricMeta; SMetricMeta* pMetricMeta = pMeterMetaInfo->pMetricMeta;
SVnodeSidList *pVnodeSidList = tscGetVnodeSidList(pMetricMeta, pMeterMetaInfo->vnodeIndex); for (int32_t i = 0; i < pMetricMeta->numOfVnodes; i++) {
numOfMeters = pVnodeSidList->numOfSids; SVnodeSidList *pVnodeSidList = tscGetVnodeSidList(pMetricMeta, pMeterMetaInfo->vnodeIndex);
numOfMeters += pVnodeSidList->numOfSids;
}
progress = calloc(numOfMeters, sizeof(SSubscriptionProgress)); progress = calloc(numOfMeters, sizeof(SSubscriptionProgress));
for (int32_t i = 0; i < numOfMeters; ++i) { numOfMeters = 0;
SMeterSidExtInfo *pMeterInfo = tscGetMeterSidInfo(pVnodeSidList, i); for (int32_t i = 0; i < pMetricMeta->numOfVnodes; i++) {
int64_t uid = pMeterInfo->uid; SVnodeSidList *pVnodeSidList = tscGetVnodeSidList(pMetricMeta, pMeterMetaInfo->vnodeIndex);
progress[i].uid = uid; for (int32_t j = 0; j < pVnodeSidList->numOfSids; j++) {
progress[i].key = tscGetSubscriptionProgress(pSub, uid); SMeterSidExtInfo *pMeterInfo = tscGetMeterSidInfo(pVnodeSidList, j);
int64_t uid = pMeterInfo->uid;
progress[numOfMeters].uid = uid;
progress[numOfMeters++].key = tscGetSubscriptionProgress(pSub, uid);
}
} }
qsort(progress, numOfMeters, sizeof(SSubscriptionProgress), tscCompareSubscriptionProgress); qsort(progress, numOfMeters, sizeof(SSubscriptionProgress), tscCompareSubscriptionProgress);
} }
...@@ -193,33 +202,26 @@ bool tscUpdateSubscription(STscObj* pObj, SSub* pSub) { ...@@ -193,33 +202,26 @@ bool tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
pSub->numOfMeters = numOfMeters; pSub->numOfMeters = numOfMeters;
pSub->progress = progress; pSub->progress = progress;
// timestamp must in the output column
SFieldInfo* pFieldInfo = &pCmd->fieldsInfo;
tscFieldInfoSetValue(pFieldInfo, pFieldInfo->numOfOutputCols, TSDB_DATA_TYPE_TIMESTAMP, "_c0", TSDB_KEYSIZE);
tscSqlExprInsertEmpty(pCmd, pFieldInfo->numOfOutputCols - 1, TSDB_FUNC_PRJ);
tscFieldInfoUpdateVisible(pFieldInfo, pFieldInfo->numOfOutputCols - 1, false);
tscFieldInfoCalOffset(pCmd);
pSub->lastSyncTime = taosGetTimestampMs(); pSub->lastSyncTime = taosGetTimestampMs();
return true; return 1;
} }
static void tscLoadSubscriptionProgress(SSub* pSub) { static int tscLoadSubscriptionProgress(SSub* pSub) {
char buf[TSDB_MAX_SQL_LEN]; char buf[TSDB_MAX_SQL_LEN];
sprintf(buf, "%s/subscribe/%s", dataDir, pSub->topic); sprintf(buf, "%s/subscribe/%s", dataDir, pSub->topic);
FILE* fp = fopen(buf, "r"); FILE* fp = fopen(buf, "r");
if (fp == NULL) { if (fp == NULL) {
tscTrace("subscription progress file does not exist: %s", pSub->topic); tscTrace("subscription progress file does not exist: %s", pSub->topic);
return true; return 1;
} }
if (fgets(buf, sizeof(buf), fp) == NULL) { if (fgets(buf, sizeof(buf), fp) == NULL) {
tscTrace("invalid subscription progress file: %s", pSub->topic); tscTrace("invalid subscription progress file: %s", pSub->topic);
fclose(fp); fclose(fp);
return false; return 0;
} }
for (int i = 0; i < sizeof(buf); i++) { for (int i = 0; i < sizeof(buf); i++) {
...@@ -233,13 +235,13 @@ static void tscLoadSubscriptionProgress(SSub* pSub) { ...@@ -233,13 +235,13 @@ static void tscLoadSubscriptionProgress(SSub* pSub) {
if (strcmp(buf, pSub->pSql->sqlstr) != 0) { if (strcmp(buf, pSub->pSql->sqlstr) != 0) {
tscTrace("subscription sql statement mismatch: %s", pSub->topic); tscTrace("subscription sql statement mismatch: %s", pSub->topic);
fclose(fp); fclose(fp);
return false; return 0;
} }
if (fgets(buf, sizeof(buf), fp) == NULL || atoi(buf) < 0) { if (fgets(buf, sizeof(buf), fp) == NULL || atoi(buf) < 0) {
tscTrace("invalid subscription progress file: %s", pSub->topic); tscTrace("invalid subscription progress file: %s", pSub->topic);
fclose(fp); fclose(fp);
return false; return 0;
} }
int numOfMeters = atoi(buf); int numOfMeters = atoi(buf);
...@@ -248,7 +250,7 @@ static void tscLoadSubscriptionProgress(SSub* pSub) { ...@@ -248,7 +250,7 @@ static void tscLoadSubscriptionProgress(SSub* pSub) {
if (fgets(buf, sizeof(buf), fp) == NULL) { if (fgets(buf, sizeof(buf), fp) == NULL) {
fclose(fp); fclose(fp);
free(progress); free(progress);
return false; return 0;
} }
int64_t uid, key; int64_t uid, key;
sscanf(buf, "uid=%" SCNd64 ",progress=%" SCNd64, &uid, &key); sscanf(buf, "uid=%" SCNd64 ",progress=%" SCNd64, &uid, &key);
...@@ -261,7 +263,8 @@ static void tscLoadSubscriptionProgress(SSub* pSub) { ...@@ -261,7 +263,8 @@ static void tscLoadSubscriptionProgress(SSub* pSub) {
qsort(progress, numOfMeters, sizeof(SSubscriptionProgress), tscCompareSubscriptionProgress); qsort(progress, numOfMeters, sizeof(SSubscriptionProgress), tscCompareSubscriptionProgress);
pSub->numOfMeters = numOfMeters; pSub->numOfMeters = numOfMeters;
pSub->progress = progress; pSub->progress = progress;
return true; tscTrace("subscription progress loaded, %d tables: %s", numOfMeters, pSub->topic);
return 1;
} }
void tscSaveSubscriptionProgress(void* sub) { void tscSaveSubscriptionProgress(void* sub) {
...@@ -291,7 +294,6 @@ void tscSaveSubscriptionProgress(void* sub) { ...@@ -291,7 +294,6 @@ void tscSaveSubscriptionProgress(void* sub) {
fclose(fp); fclose(fp);
} }
TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char *sql, TAOS_SUBSCRIBE_CALLBACK fp, void *param, int interval) { TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char *sql, TAOS_SUBSCRIBE_CALLBACK fp, void *param, int interval) {
STscObj* pObj = (STscObj*)taos; STscObj* pObj = (STscObj*)taos;
if (pObj == NULL || pObj->signature != pObj) { if (pObj == NULL || pObj->signature != pObj) {
...@@ -313,6 +315,7 @@ TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char ...@@ -313,6 +315,7 @@ TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char
} }
if (!tscUpdateSubscription(pObj, pSub)) { if (!tscUpdateSubscription(pObj, pSub)) {
taos_unsubscribe(pSub, 1);
return NULL; return NULL;
} }
...@@ -326,39 +329,55 @@ TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char ...@@ -326,39 +329,55 @@ TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char
return pSub; return pSub;
} }
void taos_free_result_imp(SSqlObj* pSql, int keepCmd);
TAOS_RES *taos_consume(TAOS_SUB *tsub) { TAOS_RES *taos_consume(TAOS_SUB *tsub) {
SSub *pSub = (SSub *)tsub; SSub *pSub = (SSub *)tsub;
if (pSub == NULL) return NULL; if (pSub == NULL) return NULL;
if (taosGetTimestampMs() - pSub->lastSyncTime > 30 * 60 * 1000) {
taos_query(pSub->taos, "reset query cache;");
// TODO: clear memory
if (!tscUpdateSubscription(pSub->taos, pSub)) return NULL;
}
SSqlObj* pSql = pSub->pSql; SSqlObj* pSql = pSub->pSql;
SSqlRes *pRes = &pSql->res; SSqlRes *pRes = &pSql->res;
pRes->numOfRows = 1; if (taosGetTimestampMs() - pSub->lastSyncTime > 10 * 1000) {
pRes->numOfTotal = 0; char* sqlstr = pSql->sqlstr;
pRes->qhandle = 0; pSql->sqlstr = NULL;
pSql->thandle = NULL; taos_free_result_imp(pSql, 0);
pSql->cmd.command = TSDB_SQL_SELECT; pSql->sqlstr = sqlstr;
taosClearDataCache(tscCacheHandle);
if (!tscUpdateSubscription(pSub->taos, pSub)) return NULL;
} else {
uint16_t type = pSql->cmd.type;
taos_free_result_imp(pSql, 1);
pRes->numOfRows = 1;
pRes->numOfTotal = 0;
pRes->qhandle = 0;
pSql->thandle = NULL;
pSql->cmd.command = TSDB_SQL_SELECT;
pSql->cmd.type = type;
}
tscDoQuery(pSql); tscDoQuery(pSql);
if (pRes->code != TSDB_CODE_SUCCESS) { if (pRes->code != TSDB_CODE_SUCCESS) {
tscRemoveFromSqlList(pSql);
return NULL; return NULL;
} }
return pSql; return pSql;
} }
void taos_unsubscribe(TAOS_SUB *tsub) { void taos_unsubscribe(TAOS_SUB *tsub, int keepProgress) {
SSub *pSub = (SSub *)tsub; SSub *pSub = (SSub *)tsub;
if (pSub == NULL || pSub->signature != pSub) return; if (pSub == NULL || pSub->signature != pSub) return;
if (pSub->pTimer != NULL) { if (pSub->pTimer != NULL) {
taosTmrStop(pSub->pTimer); taosTmrStop(pSub->pTimer);
} }
if (!keepProgress) {
char path[256];
sprintf(path, "%s/subscribe/%s", dataDir, pSub->topic);
remove(path);
}
tscFreeSqlObj(pSub->pSql); tscFreeSqlObj(pSub->pSql);
free(pSub->progress); free(pSub->progress);
memset(pSub, 0, sizeof(*pSub)); memset(pSub, 0, sizeof(*pSub));
......
...@@ -376,6 +376,21 @@ void tscFreeSqlCmdData(SSqlCmd* pCmd) { ...@@ -376,6 +376,21 @@ void tscFreeSqlCmdData(SSqlCmd* pCmd) {
} }
} }
void tscFreeSqlResult(SSqlObj* pSql) {
tfree(pSql->res.pRsp);
pSql->res.row = 0;
pSql->res.numOfRows = 0;
pSql->res.numOfTotal = 0;
pSql->res.numOfGroups = 0;
tfree(pSql->res.pGroupRec);
tscDestroyLocalReducer(pSql);
tscDestroyResPointerInfo(&pSql->res);
tfree(pSql->res.pColumnIndex);
}
void tscFreeSqlObjPartial(SSqlObj* pSql) { void tscFreeSqlObjPartial(SSqlObj* pSql) {
if (pSql == NULL || pSql->signature != pSql) { if (pSql == NULL || pSql->signature != pSql) {
return; return;
...@@ -399,20 +414,9 @@ void tscFreeSqlObjPartial(SSqlObj* pSql) { ...@@ -399,20 +414,9 @@ void tscFreeSqlObjPartial(SSqlObj* pSql) {
tfree(pSql->sqlstr); tfree(pSql->sqlstr);
pthread_mutex_unlock(&pObj->mutex); pthread_mutex_unlock(&pObj->mutex);
tfree(pSql->res.pRsp); tscFreeSqlResult(pSql);
pSql->res.row = 0;
pSql->res.numOfRows = 0;
pSql->res.numOfTotal = 0;
pSql->res.numOfGroups = 0;
tfree(pSql->res.pGroupRec);
tscDestroyLocalReducer(pSql);
tfree(pSql->pSubs); tfree(pSql->pSubs);
pSql->numOfSubs = 0; pSql->numOfSubs = 0;
tscDestroyResPointerInfo(pRes);
tfree(pSql->res.pColumnIndex);
tscFreeSqlCmdData(pCmd); tscFreeSqlCmdData(pCmd);
tscRemoveAllMeterMetaInfo(pCmd, false); tscRemoveAllMeterMetaInfo(pCmd, false);
......
...@@ -119,7 +119,7 @@ DLL_EXPORT void taos_fetch_row_a(TAOS_RES *res, void (*fp)(void *param, TAOS_RES ...@@ -119,7 +119,7 @@ DLL_EXPORT void taos_fetch_row_a(TAOS_RES *res, void (*fp)(void *param, TAOS_RES
typedef void (*TAOS_SUBSCRIBE_CALLBACK)(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code); typedef void (*TAOS_SUBSCRIBE_CALLBACK)(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code);
DLL_EXPORT TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char *sql, TAOS_SUBSCRIBE_CALLBACK fp, void *param, int interval); DLL_EXPORT TAOS_SUB *taos_subscribe(const char* topic, int restart, TAOS *taos, const char *sql, TAOS_SUBSCRIBE_CALLBACK fp, void *param, int interval);
DLL_EXPORT TAOS_RES *taos_consume(TAOS_SUB *tsub); DLL_EXPORT TAOS_RES *taos_consume(TAOS_SUB *tsub);
DLL_EXPORT void taos_unsubscribe(TAOS_SUB *tsub); DLL_EXPORT void taos_unsubscribe(TAOS_SUB *tsub, int keepProgress);
DLL_EXPORT TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, TAOS_ROW row), DLL_EXPORT TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, TAOS_ROW row),
int64_t stime, void *param, void (*callback)(void *)); int64_t stime, void *param, void (*callback)(void *));
......
...@@ -29,7 +29,8 @@ int main(int argc, char *argv[]) { ...@@ -29,7 +29,8 @@ int main(int argc, char *argv[]) {
const char* user = "root"; const char* user = "root";
const char* passwd = "taosdata"; const char* passwd = "taosdata";
const char* sql = "select * from meters;"; const char* sql = "select * from meters;";
int async = 1, restart = 0; const char* topic = "test-multiple";
int async = 1, restart = 0, keep = 1;
TAOS_SUB* tsub = NULL; TAOS_SUB* tsub = NULL;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
...@@ -55,6 +56,11 @@ int main(int argc, char *argv[]) { ...@@ -55,6 +56,11 @@ int main(int argc, char *argv[]) {
} }
if (strcmp(argv[i], "-single") == 0) { if (strcmp(argv[i], "-single") == 0) {
sql = "select * from t0;"; sql = "select * from t0;";
topic = "test-single";
continue;
}
if (strcmp(argv[i], "-nokeep") == 0) {
keep = 0;
continue; continue;
} }
} }
...@@ -69,9 +75,9 @@ int main(int argc, char *argv[]) { ...@@ -69,9 +75,9 @@ int main(int argc, char *argv[]) {
} }
if (async) { if (async) {
tsub = taos_subscribe("test", restart, taos, sql, subscribe_callback, NULL, 1000); tsub = taos_subscribe(topic, restart, taos, sql, subscribe_callback, NULL, 1000);
} else { } else {
tsub = taos_subscribe("test", restart, taos, sql, NULL, NULL, 0); tsub = taos_subscribe(topic, restart, taos, sql, NULL, NULL, 0);
} }
if (tsub == NULL) { if (tsub == NULL) {
...@@ -87,7 +93,7 @@ int main(int argc, char *argv[]) { ...@@ -87,7 +93,7 @@ int main(int argc, char *argv[]) {
getchar(); getchar();
} }
taos_unsubscribe(tsub); taos_unsubscribe(tsub, keep);
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册