streamMeta.c 12.8 KB
Newer Older
L
Liu Jicong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "executor.h"
17
#include "streamBackendRocksdb.h"
18
#include "streamInt.h"
dengyihao's avatar
dengyihao 已提交
19
#include "tref.h"
L
Liu Jicong 已提交
20
#include "ttimer.h"
L
Liu Jicong 已提交
21

dengyihao's avatar
dengyihao 已提交
22
static TdThreadOnce streamMetaModuleInit = PTHREAD_ONCE_INIT;
dengyihao's avatar
dengyihao 已提交
23
int32_t             streamBackendId = 0;
Y
yihaoDeng 已提交
24
int32_t             streamBackendCfWrapperId = 0;
Y
yihaoDeng 已提交
25 26

static void streamMetaEnvInit() {
Y
yihaoDeng 已提交
27
  streamBackendId = taosOpenRef(64, streamBackendCleanup);
Y
yihaoDeng 已提交
28
  streamBackendCfWrapperId = taosOpenRef(64, streamBackendHandleCleanup);
Y
yihaoDeng 已提交
29
}
dengyihao's avatar
dengyihao 已提交
30 31

void streamMetaInit() { taosThreadOnce(&streamMetaModuleInit, streamMetaEnvInit); }
Y
yihaoDeng 已提交
32 33
void streamMetaCleanup() {
  taosCloseRef(streamBackendId);
Y
yihaoDeng 已提交
34
  taosCloseRef(streamBackendCfWrapperId);
Y
yihaoDeng 已提交
35
}
dengyihao's avatar
dengyihao 已提交
36

37
SStreamMeta* streamMetaOpen(const char* path, void* ahandle, FTaskExpand expandFunc, int32_t vgId) {
dengyihao's avatar
dengyihao 已提交
38
  int32_t      code = -1;
L
Liu Jicong 已提交
39 40 41 42 43
  SStreamMeta* pMeta = taosMemoryCalloc(1, sizeof(SStreamMeta));
  if (pMeta == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    return NULL;
  }
44

L
Liu Jicong 已提交
45 46
  int32_t len = strlen(path) + 20;
  char*   streamPath = taosMemoryCalloc(1, len);
47
  sprintf(streamPath, "%s/%s", path, "stream");
48
  pMeta->path = taosStrdup(streamPath);
49
  if (tdbOpen(pMeta->path, 16 * 1024, 1, &pMeta->db, 0) < 0) {
L
Liu Jicong 已提交
50 51
    goto _err;
  }
dengyihao's avatar
dengyihao 已提交
52
  memset(streamPath, 0, len);
L
Liu Jicong 已提交
53

L
Liu Jicong 已提交
54
  sprintf(streamPath, "%s/%s", pMeta->path, "checkpoints");
dengyihao's avatar
dengyihao 已提交
55
  code = taosMulModeMkDir(streamPath, 0755);
dengyihao's avatar
dengyihao 已提交
56 57 58 59
  if (code != 0) {
    terrno = TAOS_SYSTEM_ERROR(code);
    goto _err;
  }
60

61
  if (tdbTbOpen("task.db", sizeof(int32_t), -1, NULL, pMeta->db, &pMeta->pTaskDb, 0) < 0) {
L
Liu Jicong 已提交
62 63 64
    goto _err;
  }

65
  if (tdbTbOpen("checkpoint.db", sizeof(int32_t), -1, NULL, pMeta->db, &pMeta->pCheckpointDb, 0) < 0) {
L
Liu Jicong 已提交
66 67 68
    goto _err;
  }

69
  _hash_fn_t fp = taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT);
H
Haojun Liao 已提交
70
  pMeta->pTasks = taosHashInit(64, fp, true, HASH_NO_LOCK);
L
Liu Jicong 已提交
71 72 73 74
  if (pMeta->pTasks == NULL) {
    goto _err;
  }

75 76 77 78 79 80 81
  // task list
  pMeta->pTaskList = taosArrayInit(4, sizeof(int32_t));
  if (pMeta->pTaskList == NULL) {
    terrno = TSDB_CODE_OUT_OF_MEMORY;
    goto _err;
  }

L
Liu Jicong 已提交
82 83 84 85
  if (streamMetaBegin(pMeta) < 0) {
    goto _err;
  }

H
Haojun Liao 已提交
86
  pMeta->walScanCounter = 0;
87
  pMeta->vgId = vgId;
L
Liu Jicong 已提交
88 89
  pMeta->ahandle = ahandle;
  pMeta->expandFunc = expandFunc;
dengyihao's avatar
dengyihao 已提交
90

dengyihao's avatar
dengyihao 已提交
91 92 93
  memset(streamPath, 0, len);
  sprintf(streamPath, "%s/%s", pMeta->path, "state");
  code = taosMulModeMkDir(streamPath, 0755);
dengyihao's avatar
dengyihao 已提交
94 95 96 97 98
  if (code != 0) {
    terrno = TAOS_SYSTEM_ERROR(code);
    goto _err;
  }

dengyihao's avatar
dengyihao 已提交
99
  pMeta->streamBackend = streamBackendInit(streamPath);
dengyihao's avatar
dengyihao 已提交
100 101 102
  if (pMeta->streamBackend == NULL) {
    goto _err;
  }
dengyihao's avatar
dengyihao 已提交
103
  pMeta->streamBackendRid = taosAddRef(streamBackendId, pMeta->streamBackend);
Y
yihaoDeng 已提交
104 105
  pMeta->pTaskBackendUnique =
      taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK);
dengyihao's avatar
dengyihao 已提交
106

dengyihao's avatar
dengyihao 已提交
107
  taosMemoryFree(streamPath);
dengyihao's avatar
dengyihao 已提交
108

109
  taosInitRWLatch(&pMeta->lock);
Y
yihaoDeng 已提交
110 111
  taosThreadMutexInit(&pMeta->backendMutex, NULL);

112
  return pMeta;
L
Liu Jicong 已提交
113

L
Liu Jicong 已提交
114
_err:
dengyihao's avatar
dengyihao 已提交
115
  taosMemoryFree(streamPath);
L
Liu Jicong 已提交
116
  taosMemoryFree(pMeta->path);
L
Liu Jicong 已提交
117
  if (pMeta->pTasks) taosHashCleanup(pMeta->pTasks);
118
  if (pMeta->pTaskList) taosArrayDestroy(pMeta->pTaskList);
L
Liu Jicong 已提交
119
  if (pMeta->pTaskDb) tdbTbClose(pMeta->pTaskDb);
120
  if (pMeta->pCheckpointDb) tdbTbClose(pMeta->pCheckpointDb);
L
Liu Jicong 已提交
121
  if (pMeta->db) tdbClose(pMeta->db);
dengyihao's avatar
dengyihao 已提交
122
  // if (pMeta->streamBackend) streamBackendCleanup(pMeta->streamBackend);
L
Liu Jicong 已提交
123
  taosMemoryFree(pMeta);
dengyihao's avatar
dengyihao 已提交
124
  qError("failed to open stream meta");
L
Liu Jicong 已提交
125 126 127 128
  return NULL;
}

void streamMetaClose(SStreamMeta* pMeta) {
129
  tdbAbort(pMeta->db, pMeta->txn);
130
  tdbTbClose(pMeta->pTaskDb);
131
  tdbTbClose(pMeta->pCheckpointDb);
132
  tdbClose(pMeta->db);
L
Liu Jicong 已提交
133 134 135 136

  void* pIter = NULL;
  while (1) {
    pIter = taosHashIterate(pMeta->pTasks, pIter);
137 138 139 140
    if (pIter == NULL) {
      break;
    }

L
Liu Jicong 已提交
141
    SStreamTask* pTask = *(SStreamTask**)pIter;
142 143 144 145 146 147 148 149
    if (pTask->schedTimer) {
      taosTmrStop(pTask->schedTimer);
      pTask->schedTimer = NULL;
    }

    if (pTask->launchTaskTimer) {
      taosTmrStop(pTask->launchTaskTimer);
      pTask->launchTaskTimer = NULL;
L
Liu Jicong 已提交
150
    }
151

152
    tFreeStreamTask(pTask);
L
Liu Jicong 已提交
153
  }
154

L
Liu Jicong 已提交
155
  taosHashCleanup(pMeta->pTasks);
dengyihao's avatar
dengyihao 已提交
156
  taosRemoveRef(streamBackendId, pMeta->streamBackendRid);
157
  pMeta->pTaskList = taosArrayDestroy(pMeta->pTaskList);
L
Liu Jicong 已提交
158
  taosMemoryFree(pMeta->path);
Y
yihaoDeng 已提交
159 160
  taosThreadMutexDestroy(&pMeta->backendMutex);
  taosHashCleanup(pMeta->pTaskBackendUnique);
L
Liu Jicong 已提交
161 162 163
  taosMemoryFree(pMeta);
}

164 165
#if 0
int32_t streamMetaAddSerializedTask(SStreamMeta* pMeta, int64_t ver, char* msg, int32_t msgLen) {
L
Liu Jicong 已提交
166 167 168 169 170 171
  SStreamTask* pTask = taosMemoryCalloc(1, sizeof(SStreamTask));
  if (pTask == NULL) {
    return -1;
  }
  SDecoder decoder;
  tDecoderInit(&decoder, (uint8_t*)msg, msgLen);
172
  if (tDecodeStreamTask(&decoder, pTask) < 0) {
L
Liu Jicong 已提交
173
    tDecoderClear(&decoder);
L
Liu Jicong 已提交
174 175 176 177
    goto FAIL;
  }
  tDecoderClear(&decoder);

178
  if (pMeta->expandFunc(pMeta->ahandle, pTask, ver) < 0) {
L
Liu Jicong 已提交
179 180 181 182
    ASSERT(0);
    goto FAIL;
  }

183
  if (taosHashPut(pMeta->pTasks, &pTask->id.taskId, sizeof(int32_t), &pTask, sizeof(void*)) < 0) {
L
Liu Jicong 已提交
184 185
    goto FAIL;
  }
L
Liu Jicong 已提交
186

187 188
  if (tdbTbUpsert(pMeta->pTaskDb, &pTask->id.taskId, sizeof(int32_t), msg, msgLen, pMeta->txn) < 0) {
    taosHashRemove(pMeta->pTasks, &pTask->id.taskId, sizeof(int32_t));
L
Liu Jicong 已提交
189
    ASSERT(0);
L
Liu Jicong 已提交
190
    goto FAIL;
L
Liu Jicong 已提交
191
  }
L
Liu Jicong 已提交
192

L
Liu Jicong 已提交
193 194 195
  return 0;

FAIL:
196
  if (pTask) tFreeStreamTask(pTask);
L
Liu Jicong 已提交
197
  return -1;
L
Liu Jicong 已提交
198
}
199
#endif
L
Liu Jicong 已提交
200

L
Liu Jicong 已提交
201 202
int32_t streamMetaSaveTask(SStreamMeta* pMeta, SStreamTask* pTask) {
  void*   buf = NULL;
L
Liu Jicong 已提交
203 204
  int32_t len;
  int32_t code;
205
  tEncodeSize(tEncodeStreamTask, pTask, len, code);
L
Liu Jicong 已提交
206 207 208
  if (code < 0) {
    return -1;
  }
L
Liu Jicong 已提交
209
  buf = taosMemoryCalloc(1, len);
L
Liu Jicong 已提交
210 211 212 213
  if (buf == NULL) {
    return -1;
  }

214
  SEncoder encoder = {0};
L
Liu Jicong 已提交
215
  tEncoderInit(&encoder, buf, len);
216
  tEncodeStreamTask(&encoder, pTask);
217
  tEncoderClear(&encoder);
L
Liu Jicong 已提交
218

219
  if (tdbTbUpsert(pMeta->pTaskDb, &pTask->id.taskId, sizeof(int32_t), buf, len, pMeta->txn) < 0) {
L
Liu Jicong 已提交
220 221 222
    return -1;
  }

L
Liu Jicong 已提交
223
  taosMemoryFree(buf);
L
Liu Jicong 已提交
224 225 226
  return 0;
}

227 228
// add to the ready tasks hash map, not the restored tasks hash map
int32_t streamMetaAddDeployedTask(SStreamMeta* pMeta, int64_t ver, SStreamTask* pTask) {
229 230
  void* p = taosHashGet(pMeta->pTasks, &pTask->id.taskId, sizeof(pTask->id.taskId));
  if (p == NULL) {
231 232 233 234 235 236 237 238 239 240 241 242 243 244
    if (pMeta->expandFunc(pMeta->ahandle, pTask, ver) < 0) {
      tFreeStreamTask(pTask);
      return -1;
    }

    if (streamMetaSaveTask(pMeta, pTask) < 0) {
      tFreeStreamTask(pTask);
      return -1;
    }

    if (streamMetaCommit(pMeta) < 0) {
      tFreeStreamTask(pTask);
      return -1;
    }
245
    taosArrayPush(pMeta->pTaskList, &pTask->id.taskId);
246 247
  } else {
    return 0;
248 249 250
  }

  taosHashPut(pMeta->pTasks, &pTask->id.taskId, sizeof(pTask->id.taskId), &pTask, POINTER_BYTES);
L
Liu Jicong 已提交
251 252
  return 0;
}
253 254

int32_t streamMetaGetNumOfTasks(const SStreamMeta* pMeta) {
255 256 257
  size_t size = taosHashGetSize(pMeta->pTasks);
  ASSERT(taosArrayGetSize(pMeta->pTaskList) == taosHashGetSize(pMeta->pTasks));

258
  return (int32_t)size;
259
}
L
Liu Jicong 已提交
260

L
Liu Jicong 已提交
261 262 263 264
SStreamTask* streamMetaAcquireTask(SStreamMeta* pMeta, int32_t taskId) {
  taosRLockLatch(&pMeta->lock);

  SStreamTask** ppTask = (SStreamTask**)taosHashGet(pMeta->pTasks, &taskId, sizeof(int32_t));
265
  if (ppTask != NULL) {
266
    if (!streamTaskShouldStop(&(*ppTask)->status)) {
H
Haojun Liao 已提交
267
      int32_t ref = atomic_add_fetch_32(&(*ppTask)->refCnt, 1);
268
      taosRUnLockLatch(&pMeta->lock);
H
Haojun Liao 已提交
269
      qDebug("s-task:%s acquire task, ref:%d", (*ppTask)->id.idStr, ref);
270 271
      return *ppTask;
    }
L
Liu Jicong 已提交
272
  }
273

L
Liu Jicong 已提交
274 275 276 277 278
  taosRUnLockLatch(&pMeta->lock);
  return NULL;
}

void streamMetaReleaseTask(SStreamMeta* pMeta, SStreamTask* pTask) {
H
Haojun Liao 已提交
279 280 281 282
  int32_t ref = atomic_sub_fetch_32(&pTask->refCnt, 1);
  if (ref > 0) {
    qDebug("s-task:%s release task, ref:%d", pTask->id.idStr, ref);
  } else if (ref == 0) {
283
    ASSERT(streamTaskShouldStop(&pTask->status));
284
    tFreeStreamTask(pTask);
H
Haojun Liao 已提交
285 286 287 288 289 290 291 292 293 294 295 296
  } else if (ref < 0) {
    qError("task ref is invalid, ref:%d, %s", ref, pTask->id.idStr);
  }
}

static void doRemoveIdFromList(SStreamMeta* pMeta, int32_t num, int32_t taskId) {
  for (int32_t i = 0; i < num; ++i) {
    int32_t* pTaskId = taosArrayGet(pMeta->pTaskList, i);
    if (*pTaskId == taskId) {
      taosArrayRemove(pMeta->pTaskList, i);
      break;
    }
L
Liu Jicong 已提交
297 298 299
  }
}

300
void streamMetaRemoveTask(SStreamMeta* pMeta, int32_t taskId) {
H
Haojun Liao 已提交
301
  SStreamTask* pTask = NULL;
H
Haojun Liao 已提交
302

H
Haojun Liao 已提交
303 304
  // pre-delete operation
  taosWLockLatch(&pMeta->lock);
L
Liu Jicong 已提交
305 306
  SStreamTask** ppTask = (SStreamTask**)taosHashGet(pMeta->pTasks, &taskId, sizeof(int32_t));
  if (ppTask) {
H
Haojun Liao 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    pTask = *ppTask;
    atomic_store_8(&pTask->status.taskStatus, TASK_STATUS__DROPPING);
  } else {
    qDebug("vgId:%d failed to find the task:0x%x, it may be dropped already", pMeta->vgId, taskId);
    taosWUnLockLatch(&pMeta->lock);
    return;
  }
  taosWUnLockLatch(&pMeta->lock);

  qDebug("s-task:0x%x set task status:%s", taskId, streamGetTaskStatusStr(TASK_STATUS__DROPPING));

  while(1) {
    taosRLockLatch(&pMeta->lock);
    ppTask = (SStreamTask**)taosHashGet(pMeta->pTasks, &taskId, sizeof(int32_t));

    if (ppTask) {
      if ((*ppTask)->status.timerActive == 0) {
        taosRUnLockLatch(&pMeta->lock);
        break;
      }
327

H
Haojun Liao 已提交
328 329 330 331 332 333 334 335 336 337 338 339 340
      taosMsleep(10);
      qDebug("s-task:%s wait for quit from timer", (*ppTask)->id.idStr);
      taosRUnLockLatch(&pMeta->lock);
    } else {
      taosRUnLockLatch(&pMeta->lock);
      break;
    }
  }

  // let's do delete of stream task
  taosWLockLatch(&pMeta->lock);
  ppTask = (SStreamTask**)taosHashGet(pMeta->pTasks, &taskId, sizeof(int32_t));
  if (ppTask) {
L
Liu Jicong 已提交
341
    taosHashRemove(pMeta->pTasks, &taskId, sizeof(int32_t));
L
Liu Jicong 已提交
342
    tdbTbDelete(pMeta->pTaskDb, &taskId, sizeof(int32_t), pMeta->txn);
343

dengyihao's avatar
dengyihao 已提交
344
    atomic_store_8(&pTask->status.taskStatus, TASK_STATUS__DROPPING);
H
Haojun Liao 已提交
345
    ASSERT(pTask->status.timerActive == 0);
346

H
Haojun Liao 已提交
347
    int32_t num = taosArrayGetSize(pMeta->pTaskList);
348
    qDebug("s-task:%s set the drop task flag, remain running s-task:%d", pTask->id.idStr, num - 1);
H
Haojun Liao 已提交
349 350 351 352 353 354
    doRemoveIdFromList(pMeta, num, pTask->id.taskId);

    // remove the ref by timer
    if (pTask->triggerParam != 0) {
      taosTmrStop(pTask->schedTimer);
      streamMetaReleaseTask(pMeta, pTask);
355 356
    }

L
Liu Jicong 已提交
357
    streamMetaReleaseTask(pMeta, pTask);
358
  } else {
H
Haojun Liao 已提交
359
    qDebug("vgId:%d failed to find the task:0x%x, it may have been dropped already", pMeta->vgId, taskId);
L
Liu Jicong 已提交
360
  }
H
Haojun Liao 已提交
361 362

  taosWUnLockLatch(&pMeta->lock);
L
Liu Jicong 已提交
363 364
}

L
Liu Jicong 已提交
365
int32_t streamMetaBegin(SStreamMeta* pMeta) {
366 367
  if (tdbBegin(pMeta->db, &pMeta->txn, tdbDefaultMalloc, tdbDefaultFree, NULL,
               TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
L
Liu Jicong 已提交
368 369 370 371 372
    return -1;
  }
  return 0;
}

373
// todo add error log
L
Liu Jicong 已提交
374
int32_t streamMetaCommit(SStreamMeta* pMeta) {
375
  if (tdbCommit(pMeta->db, pMeta->txn) < 0) {
376
    qError("failed to commit stream meta");
L
Liu Jicong 已提交
377 378
    return -1;
  }
379

380
  if (tdbPostCommit(pMeta->db, pMeta->txn) < 0) {
381
    qError("failed to commit stream meta");
382 383
    return -1;
  }
384 385 386

  if (tdbBegin(pMeta->db, &pMeta->txn, tdbDefaultMalloc, tdbDefaultFree, NULL,
               TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
387 388
    return -1;
  }
389

L
Liu Jicong 已提交
390 391 392
  return 0;
}

393
int32_t streamMetaAbort(SStreamMeta* pMeta) {
394
  if (tdbAbort(pMeta->db, pMeta->txn) < 0) {
395 396
    return -1;
  }
397 398 399

  if (tdbBegin(pMeta->db, &pMeta->txn, tdbDefaultMalloc, tdbDefaultFree, NULL,
               TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED) < 0) {
400 401
    return -1;
  }
L
Liu Jicong 已提交
402 403
  return 0;
}
404

L
Liu Jicong 已提交
405
int32_t streamLoadTasks(SStreamMeta* pMeta, int64_t ver) {
L
Liu Jicong 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  TBC* pCur = NULL;
  if (tdbTbcOpen(pMeta->pTaskDb, &pCur, NULL) < 0) {
    return -1;
  }

  void*    pKey = NULL;
  int32_t  kLen = 0;
  void*    pVal = NULL;
  int32_t  vLen = 0;
  SDecoder decoder;

  tdbTbcMoveToFirst(pCur);

  while (tdbTbcNext(pCur, &pKey, &kLen, &pVal, &vLen) == 0) {
    SStreamTask* pTask = taosMemoryCalloc(1, sizeof(SStreamTask));
    if (pTask == NULL) {
L
Liu Jicong 已提交
422 423
      tdbFree(pKey);
      tdbFree(pVal);
5
54liuyao 已提交
424
      tdbTbcClose(pCur);
L
Liu Jicong 已提交
425 426
      return -1;
    }
427

L
Liu Jicong 已提交
428
    tDecoderInit(&decoder, (uint8_t*)pVal, vLen);
429
    tDecodeStreamTask(&decoder, pTask);
L
Liu Jicong 已提交
430
    tDecoderClear(&decoder);
431

432
    // remove duplicate
433 434
    void* p = taosHashGet(pMeta->pTasks, &pTask->id.taskId, sizeof(pTask->id.taskId));
    if (p == NULL) {
435 436 437 438
      if (pMeta->expandFunc(pMeta->ahandle, pTask, pTask->chkInfo.version) < 0) {
        tdbFree(pKey);
        tdbFree(pVal);
        tdbTbcClose(pCur);
439
        taosMemoryFree(pTask);
440 441
        return -1;
      }
442
      taosArrayPush(pMeta->pTaskList, &pTask->id.taskId);
443
    } else {
444 445 446 447
      tdbFree(pKey);
      tdbFree(pVal);
      tdbTbcClose(pCur);
      taosMemoryFree(pTask);
448
      continue;
449
    }
450

451
    if (taosHashPut(pMeta->pTasks, &pTask->id.taskId, sizeof(pTask->id.taskId), &pTask, sizeof(void*)) < 0) {
L
Liu Jicong 已提交
452 453
      tdbFree(pKey);
      tdbFree(pVal);
5
54liuyao 已提交
454
      tdbTbcClose(pCur);
455
      taosMemoryFree(pTask);
456 457
      return -1;
    }
458

459
    ASSERT(pTask->status.downstreamReady == 0);
460 461
  }

462 463
  tdbFree(pKey);
  tdbFree(pVal);
464 465
  if (tdbTbcClose(pCur) < 0) {
    return -1;
L
Liu Jicong 已提交
466 467 468 469
  }

  return 0;
}