tqMetaStore.c 14.1 KB
Newer Older
L
Liu Jicong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * 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/>.
 */
L
Liu Jicong 已提交
15
#include "tqMetaStore.h"
L
Liu Jicong 已提交
16
//TODO:replace by an abstract file layer
L
Liu Jicong 已提交
17
#include "osDir.h"
L
Liu Jicong 已提交
18
#include <fcntl.h>
L
Liu Jicong 已提交
19
#include <string.h>
L
Liu Jicong 已提交
20 21
#include <unistd.h>

L
Liu Jicong 已提交
22 23 24
#define TQ_META_NAME "tq.meta"
#define TQ_IDX_NAME  "tq.idx"

L
Liu Jicong 已提交
25

L
Liu Jicong 已提交
26 27
static int32_t tqHandlePutCommitted(TqMetaStore*, int64_t key, void* value);
static void*   tqHandleGetUncommitted(TqMetaStore*, int64_t key);
L
Liu Jicong 已提交
28

L
Liu Jicong 已提交
29 30 31 32 33
typedef struct TqMetaPageBuf {
  int16_t offset;
  char buffer[TQ_PAGE_SIZE];
} TqMetaPageBuf;

L
Liu Jicong 已提交
34
TqMetaStore* tqStoreOpen(const char* path,
L
Liu Jicong 已提交
35 36 37
    int serializer(const void* pObj, void** ppBytes),
    const void* deserializer(const void* pBytes, void** ppObj),
    void deleter(void* pObj)) {
L
Liu Jicong 已提交
38 39 40 41 42
  TqMetaStore* pMeta = malloc(sizeof(TqMetaStore)); 
  if(pMeta == NULL) {
    //close
    return NULL;
  }
L
Liu Jicong 已提交
43
  memset(pMeta, 0, sizeof(TqMetaStore));
L
Liu Jicong 已提交
44 45 46

  //concat data file name and index file name
  size_t pathLen = strlen(path);
L
Liu Jicong 已提交
47 48 49 50 51 52
  pMeta->dirPath = malloc(pathLen+1);
  if(pMeta->dirPath != NULL) {
    //TODO: memory insufficient
  }
  strcpy(pMeta->dirPath, path);
  
L
Liu Jicong 已提交
53 54
  char name[pathLen+10];

L
Liu Jicong 已提交
55
  strcpy(name, path);
L
Liu Jicong 已提交
56 57 58
  if(!taosDirExist(name) && !taosMkDir(name)) {
    ASSERT(false);
  }
L
Liu Jicong 已提交
59
  strcat(name, "/" TQ_IDX_NAME);
L
Liu Jicong 已提交
60
  int idxFd = open(name, O_RDWR | O_CREAT, 0755);
L
Liu Jicong 已提交
61
  if(idxFd < 0) {
L
Liu Jicong 已提交
62
    ASSERT(false);
L
Liu Jicong 已提交
63 64 65 66
    //close file
    //free memory
    return NULL;
  }
L
Liu Jicong 已提交
67

L
Liu Jicong 已提交
68 69 70
  pMeta->idxFd = idxFd;
  pMeta->unpersistHead = malloc(sizeof(TqMetaList));
  if(pMeta->unpersistHead == NULL) {
L
Liu Jicong 已提交
71
    ASSERT(false);
L
Liu Jicong 已提交
72 73 74 75
    //close file
    //free memory
    return NULL;
  }
L
Liu Jicong 已提交
76 77 78 79
  memset(pMeta->unpersistHead, 0, sizeof(TqMetaList));
  pMeta->unpersistHead->unpersistNext
    = pMeta->unpersistHead->unpersistPrev
    = pMeta->unpersistHead;
L
Liu Jicong 已提交
80 81 82

  strcpy(name, path);
  strcat(name, "/" TQ_META_NAME);
L
Liu Jicong 已提交
83 84 85 86 87
  int fileFd = open(name, O_RDWR | O_CREAT, 0755);
  if(fileFd < 0){
    ASSERT(false);
    return NULL;
  }
L
Liu Jicong 已提交
88 89 90

  pMeta->fileFd = fileFd;
  
L
Liu Jicong 已提交
91 92 93
  pMeta->serializer = serializer;
  pMeta->deserializer = deserializer;
  pMeta->deleter = deleter;
L
Liu Jicong 已提交
94 95

  //read idx file and load into memory
L
Liu Jicong 已提交
96 97 98 99 100 101 102 103 104 105 106 107
  char idxBuf[TQ_PAGE_SIZE];
  char* dataBuf = malloc(TQ_PAGE_SIZE);
  if(dataBuf == NULL) {
    //TODO:memory insufficient
  }
  int dataBufSize = TQ_PAGE_SIZE;
  int idxRead, dataReadSize;
  while((idxRead = read(idxFd, idxBuf, TQ_PAGE_SIZE))) {
    if(idxRead == -1) {
      //TODO: handle error
      ASSERT(false);
    }
L
Liu Jicong 已提交
108
    //loop read every entry
L
Liu Jicong 已提交
109 110
    for(int i = 0; i < idxRead; i += TQ_IDX_ENTRY_SIZE) {
      TqMetaList *pNode = malloc(sizeof(TqMetaList));
L
Liu Jicong 已提交
111 112 113
      if(pNode == NULL) {
        //TODO: free memory and return error
      }
L
Liu Jicong 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
      memset(pNode, 0, sizeof(TqMetaList));
      memcpy(&pNode->handle, &idxBuf[i], TQ_IDX_ENTRY_SIZE);
      lseek(fileFd, pNode->handle.offset, SEEK_CUR);
      if(dataBufSize < pNode->handle.serializedSize) {
        void *ptr = realloc(dataBuf, pNode->handle.serializedSize);
        if(ptr == NULL) {
          //TODO: memory insufficient
        }
        dataBuf = ptr;
        dataBufSize = pNode->handle.serializedSize;
      }
      if(read(fileFd, dataBuf, pNode->handle.serializedSize) != pNode->handle.serializedSize) {
        //TODO: read error
      }
      pMeta->deserializer(dataBuf, &pNode->handle.valueInUse);

      //put into list
L
Liu Jicong 已提交
131 132 133 134 135
      int bucketKey = pNode->handle.key & TQ_BUCKET_SIZE;
      pNode->next = pMeta->bucket[bucketKey];
      pMeta->bucket[bucketKey] = pNode;
    }
  }
L
Liu Jicong 已提交
136
  free(dataBuf);
L
Liu Jicong 已提交
137 138 139 140 141
  return pMeta;
}

int32_t tqStoreClose(TqMetaStore* pMeta) {
  //commit data and idx
L
Liu Jicong 已提交
142 143 144 145
  tqStorePersist(pMeta);
  ASSERT(pMeta->unpersistHead && pMeta->unpersistHead->next==NULL);
  close(pMeta->fileFd);
  close(pMeta->idxFd);
L
Liu Jicong 已提交
146
  //free memory
L
Liu Jicong 已提交
147
  for(int i = 0; i < TQ_BUCKET_SIZE; i++) {
L
Liu Jicong 已提交
148
    TqMetaList* pNode = pMeta->bucket[i];
L
Liu Jicong 已提交
149
    pMeta->bucket[i] = NULL;
L
Liu Jicong 已提交
150 151 152 153 154
    while(pNode) {
      ASSERT(pNode->unpersistNext == NULL);
      ASSERT(pNode->unpersistPrev == NULL);
      if(pNode->handle.valueInTxn) {
        pMeta->deleter(pNode->handle.valueInTxn);
L
Liu Jicong 已提交
155
      }
L
Liu Jicong 已提交
156 157
      if(pNode->handle.valueInUse) {
        pMeta->deleter(pNode->handle.valueInUse);
L
Liu Jicong 已提交
158
      }
L
Liu Jicong 已提交
159 160 161
      TqMetaList* next = pNode->next;
      free(pNode);
      pNode = next;
L
Liu Jicong 已提交
162 163
    }
  }
L
Liu Jicong 已提交
164
  free(pMeta->dirPath);
L
Liu Jicong 已提交
165
  free(pMeta->unpersistHead);
L
Liu Jicong 已提交
166
  free(pMeta);
L
Liu Jicong 已提交
167 168 169 170
  return 0;
}

int32_t tqStoreDelete(TqMetaStore* pMeta) {
L
Liu Jicong 已提交
171 172
  close(pMeta->fileFd);
  close(pMeta->idxFd);
L
Liu Jicong 已提交
173
  //free memory
L
Liu Jicong 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
  for(int i = 0; i < TQ_BUCKET_SIZE; i++) {
    TqMetaList* pNode = pMeta->bucket[i];
    pMeta->bucket[i] = NULL;
    while(pNode) {
      if(pNode->handle.valueInTxn) {
        pMeta->deleter(pNode->handle.valueInTxn);
      }
      if(pNode->handle.valueInUse) {
        pMeta->deleter(pNode->handle.valueInUse);
      }
      TqMetaList* next = pNode->next;
      free(pNode);
      pNode = next;
    }
  }
  free(pMeta->unpersistHead);
  taosRemoveDir(pMeta->dirPath);
  free(pMeta->dirPath);
  free(pMeta);
L
Liu Jicong 已提交
193 194 195
  return 0;
}

L
Liu Jicong 已提交
196
//TODO: wrap in tfile
L
Liu Jicong 已提交
197
int32_t tqStorePersist(TqMetaStore* pMeta) {
L
Liu Jicong 已提交
198 199
  char writeBuf[TQ_PAGE_SIZE];
  int64_t* bufPtr = (int64_t*)writeBuf;
L
Liu Jicong 已提交
200 201 202
  TqMetaList *pHead = pMeta->unpersistHead;
  TqMetaList *pNode = pHead->unpersistNext;
  while(pHead != pNode) {
L
Liu Jicong 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    if(pNode->handle.valueInUse == NULL) {
      //put delete token in data file
      uint32_t delete = TQ_ACTION_DELETE;
      int nBytes = write(pMeta->fileFd, &delete, sizeof(uint32_t));
      ASSERT(nBytes == sizeof(uint32_t));

      //remove from list
      int bucketKey = pNode->handle.key & TQ_BUCKET_SIZE;
      TqMetaList* pBucketHead = pMeta->bucket[bucketKey];
      if(pBucketHead == pNode) {
        pMeta->bucket[bucketKey] = pBucketHead->next;
      } else {
        TqMetaList* pBucketNode = pBucketHead;
        while(pBucketNode->next != NULL
            && pBucketNode->next != pNode) {
          pBucketNode = pBucketNode->next; 
        }
        if(pBucketNode->next != NULL) {
          ASSERT(pBucketNode->next == pNode);
          pBucketNode->next = pNode->next;
          if(pNode->handle.valueInUse) {
            pMeta->deleter(pNode->handle.valueInUse);
L
Liu Jicong 已提交
225
            pNode->handle.valueInUse = NULL;
L
Liu Jicong 已提交
226 227 228 229
          }
          free(pNode);
        }
      }
L
Liu Jicong 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242
    } else {
      //TODO: do not allocate each time
      //serialize
      void* pBytes = NULL;
      int sz = pMeta->serializer(pNode->handle.valueInUse, &pBytes);
      ASSERT(pBytes != NULL);
      //get current offset
      //append data
      int64_t offset = lseek(pMeta->fileFd, 0, SEEK_CUR);
      int nBytes = write(pMeta->fileFd, pBytes, sz);
      free(pBytes);
      //TODO: handle error in tfile
      ASSERT(nBytes == sz);
L
Liu Jicong 已提交
243

L
Liu Jicong 已提交
244 245
      pNode->handle.offset = offset;
      pNode->handle.serializedSize = sz;
L
Liu Jicong 已提交
246

L
Liu Jicong 已提交
247 248 249 250 251 252 253 254 255 256 257 258
      //write idx
      //TODO: endian check and convert
      *(bufPtr++) = pNode->handle.key;
      *(bufPtr++) = pNode->handle.offset;
      *(bufPtr++) = (int64_t)sz;
      if((char*)(bufPtr + 3) > writeBuf + TQ_PAGE_SIZE) {
        nBytes = write(pMeta->idxFd, writeBuf, sizeof(writeBuf));
        //TODO: handle error in tfile
        ASSERT(nBytes == sizeof(writeBuf));
        memset(writeBuf, 0, TQ_PAGE_SIZE);
        bufPtr = (int64_t*)writeBuf;
      }
L
Liu Jicong 已提交
259
    }
L
Liu Jicong 已提交
260

L
Liu Jicong 已提交
261
    //remove from unpersist list
L
Liu Jicong 已提交
262 263 264 265 266
    pHead->unpersistNext = pNode->unpersistNext;
    pHead->unpersistNext->unpersistPrev = pHead;

    pNode->unpersistPrev = pNode->unpersistNext = NULL;
    pNode = pHead->unpersistNext;
L
Liu Jicong 已提交
267
  }
L
Liu Jicong 已提交
268 269 270 271 272 273 274 275 276 277
  //write left bytes
  if((char*)bufPtr != writeBuf) {
    int used = (char*)bufPtr - writeBuf;
    int nBytes = write(pMeta->idxFd, writeBuf, used);
    //TODO: handle error in tfile
    ASSERT(nBytes == used);
  }
  //TODO: using fsync in tfile
  fsync(pMeta->idxFd);
  fsync(pMeta->fileFd);
L
Liu Jicong 已提交
278 279 280
  return 0;
}

L
Liu Jicong 已提交
281
static int32_t tqHandlePutCommitted(TqMetaStore* pMeta, int64_t key, void* value) {
L
Liu Jicong 已提交
282 283 284 285 286
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      //TODO: think about thread safety
L
Liu Jicong 已提交
287 288 289
      if(pNode->handle.valueInUse) {
        pMeta->deleter(pNode->handle.valueInUse);
      }
L
Liu Jicong 已提交
290 291
      //change pointer ownership
      pNode->handle.valueInUse = value;
L
Liu Jicong 已提交
292
      return 0;
L
Liu Jicong 已提交
293 294 295 296
    } else {
      pNode = pNode->next;
    }
  }
L
Liu Jicong 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309
  TqMetaList *pNewNode = malloc(sizeof(TqMetaList));
  if(pNewNode == NULL) {
    //TODO: memory error
    return -1;
  }
  memset(pNewNode, 0, sizeof(TqMetaList));
  pNewNode->handle.key = key;
  pNewNode->handle.valueInUse = value;
  //put into unpersist list
  pNewNode->unpersistPrev = pMeta->unpersistHead;
  pNewNode->unpersistNext = pMeta->unpersistHead->unpersistNext;
  pMeta->unpersistHead->unpersistNext->unpersistPrev = pNewNode;
  pMeta->unpersistHead->unpersistNext = pNewNode;
L
Liu Jicong 已提交
310 311 312
  return 0;
}

L
Liu Jicong 已提交
313
void* tqHandleGet(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
314 315 316 317 318
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      if(pNode->handle.valueInUse != NULL) {
L
Liu Jicong 已提交
319
        return pNode->handle.valueInUse;
L
Liu Jicong 已提交
320 321 322 323 324 325 326
      } else {
        return NULL;
      }
    } else {
      pNode = pNode->next;
    }
  }
L
Liu Jicong 已提交
327 328 329
  return NULL;
}

L
Liu Jicong 已提交
330
int32_t tqHandleMovePut(TqMetaStore* pMeta, int64_t key, void* value) {
L
Liu Jicong 已提交
331 332 333 334 335
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      //TODO: think about thread safety
L
Liu Jicong 已提交
336 337 338
      if(pNode->handle.valueInTxn) {
        pMeta->deleter(pNode->handle.valueInTxn);
      }
L
Liu Jicong 已提交
339 340
      //change pointer ownership
      pNode->handle.valueInTxn = value;
L
Liu Jicong 已提交
341
      return 0;
L
Liu Jicong 已提交
342 343 344 345
    } else {
      pNode = pNode->next;
    }
  }
L
Liu Jicong 已提交
346 347 348 349 350 351 352 353
  TqMetaList *pNewNode = malloc(sizeof(TqMetaList));
  if(pNewNode == NULL) {
    //TODO: memory error
    return -1;
  }
  memset(pNewNode, 0, sizeof(TqMetaList));
  pNewNode->handle.key = key;
  pNewNode->handle.valueInTxn = value;
L
Liu Jicong 已提交
354
  pNewNode->next = pMeta->bucket[bucketKey];
L
Liu Jicong 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
  pMeta->bucket[bucketKey] = pNewNode;
  return 0;
}

int32_t tqHandleCopyPut(TqMetaStore* pMeta, int64_t key, void* value, size_t vsize) {
  void *vmem = malloc(vsize);
  if(vmem == NULL) {
    //TODO: memory error
    return -1;
  }
  memcpy(vmem, value, vsize);
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      //TODO: think about thread safety
      if(pNode->handle.valueInTxn) {
        pMeta->deleter(pNode->handle.valueInTxn);
      }
      //change pointer ownership
      pNode->handle.valueInTxn = vmem;
      return 0;
    } else {
      pNode = pNode->next;
    }
  }
  TqMetaList *pNewNode = malloc(sizeof(TqMetaList));
  if(pNewNode == NULL) {
    //TODO: memory error
    return -1;
  }
  memset(pNewNode, 0, sizeof(TqMetaList));
  pNewNode->handle.key = key;
  pNewNode->handle.valueInTxn = vmem;
  pNewNode->next = pMeta->bucket[bucketKey];
L
Liu Jicong 已提交
390
  pMeta->bucket[bucketKey] = pNewNode;
L
Liu Jicong 已提交
391 392 393
  return 0;
}

L
Liu Jicong 已提交
394
static void* tqHandleGetUncommitted(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
395 396 397 398 399
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      if(pNode->handle.valueInTxn != NULL) {
L
Liu Jicong 已提交
400
        return pNode->handle.valueInTxn;
L
Liu Jicong 已提交
401 402 403 404 405 406 407
      } else {
        return NULL;
      }
    } else {
      pNode = pNode->next;
    }
  }
L
Liu Jicong 已提交
408 409 410 411
  return NULL;
}

int32_t tqHandleCommit(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
412 413 414 415
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
L
Liu Jicong 已提交
416
      if(pNode->handle.valueInUse) {
L
Liu Jicong 已提交
417 418 419
        pMeta->deleter(pNode->handle.valueInUse);
      }
      pNode->handle.valueInUse = pNode->handle.valueInTxn;
L
Liu Jicong 已提交
420
      pNode->handle.valueInTxn = NULL;
L
Liu Jicong 已提交
421 422 423 424 425 426 427 428 429 430 431 432
      if(pNode->unpersistNext == NULL) {
        pNode->unpersistNext = pMeta->unpersistHead->unpersistNext;
        pNode->unpersistPrev = pMeta->unpersistHead;
        pMeta->unpersistHead->unpersistNext->unpersistPrev = pNode;
        pMeta->unpersistHead->unpersistNext = pNode;
      }
      return 0;
    } else {
      pNode = pNode->next;
    }
  }
  return -1;
L
Liu Jicong 已提交
433 434 435
}

int32_t tqHandleAbort(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
      if(pNode->handle.valueInTxn != NULL) {
        pMeta->deleter(pNode->handle.valueInTxn);
        pNode->handle.valueInTxn = NULL;
        return 0;
      }
      return -1;
    } else {
      pNode = pNode->next;
    }
  }
  return -2;
L
Liu Jicong 已提交
451 452 453
}

int32_t tqHandleDel(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
454 455 456 457
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  while(pNode) {
    if(pNode->handle.key == key) {
L
Liu Jicong 已提交
458 459 460
      pMeta->deleter(pNode->handle.valueInTxn);
      pNode->handle.valueInTxn = NULL;
      return 0;
L
Liu Jicong 已提交
461 462 463 464
    } else {
      pNode = pNode->next;
    }
  }
L
Liu Jicong 已提交
465 466
  //no such key
  return -1;
L
Liu Jicong 已提交
467 468 469
}

int32_t tqHandleClear(TqMetaStore* pMeta, int64_t key) {
L
Liu Jicong 已提交
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
  int64_t bucketKey = key & TQ_BUCKET_SIZE;
  TqMetaList* pNode = pMeta->bucket[bucketKey];
  bool exist = false;
  while(pNode) {
    if(pNode->handle.key == key) {
      if(pNode->handle.valueInUse != NULL) {
        exist = true;
        pMeta->deleter(pNode->handle.valueInUse);
        pNode->handle.valueInUse = NULL;
      }
      if(pNode->handle.valueInTxn != NULL) {
        exist = true;
        pMeta->deleter(pNode->handle.valueInTxn);
        pNode->handle.valueInTxn = NULL;
      }
      if(exist) {
        if(pNode->unpersistNext == NULL) {
          pNode->unpersistNext = pMeta->unpersistHead->unpersistNext;
          pNode->unpersistPrev = pMeta->unpersistHead;
          pMeta->unpersistHead->unpersistNext->unpersistPrev = pNode;
          pMeta->unpersistHead->unpersistNext = pNode;
        }
        return 0;
      }
      return -1;
    } else {
      pNode = pNode->next;
    }
  }
  return -2;
L
Liu Jicong 已提交
500
}