indexFstFile.c 8.9 KB
Newer Older
dengyihao's avatar
dengyihao 已提交
1 2 3 4 5 6
/*
 * 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.
dengyihao's avatar
dengyihao 已提交
7
 * * This program is distributed in the hope that it will be useful, but WITHOUT
dengyihao's avatar
dengyihao 已提交
8 9 10 11 12 13
 * 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/>.
 */
S
Shengliang Guan 已提交
14

dengyihao's avatar
dengyihao 已提交
15
#include "indexFstFile.h"
dengyihao's avatar
dengyihao 已提交
16
#include "indexComm.h"
dengyihao's avatar
dengyihao 已提交
17
#include "indexFstUtil.h"
dengyihao's avatar
dengyihao 已提交
18
#include "indexInt.h"
dengyihao's avatar
dengyihao 已提交
19
#include "indexUtil.h"
dengyihao's avatar
dengyihao 已提交
20
#include "os.h"
dengyihao's avatar
dengyihao 已提交
21
#include "osDef.h"
22
#include "tutil.h"
dengyihao's avatar
dengyihao 已提交
23

dengyihao's avatar
dengyihao 已提交
24 25 26 27 28 29 30 31
static int32_t kBlockSize = 4096;

typedef struct {
  int32_t blockId;
  int32_t nread;
  char    buf[0];
} SDataBlock;

D
dapan1121 已提交
32 33 34 35
static void deleteDataBlockFromLRU(const void* key, size_t keyLen, void* value, void* ud) {
  (void)ud;
  taosMemoryFree(value);
}
dengyihao's avatar
dengyihao 已提交
36

dengyihao's avatar
dengyihao 已提交
37
static FORCE_INLINE void idxGenLRUKey(char* buf, const char* path, int32_t blockId) {
dengyihao's avatar
dengyihao 已提交
38 39 40 41 42 43
  char* p = buf;
  SERIALIZE_STR_VAR_TO_BUF(p, path, strlen(path));
  SERIALIZE_VAR_TO_BUF(p, '_', char);
  idxInt2str(blockId, p, 0);
  return;
}
dengyihao's avatar
dengyihao 已提交
44
static FORCE_INLINE int idxFileCtxDoWrite(IFileCtx* ctx, uint8_t* buf, int len) {
dengyihao's avatar
dengyihao 已提交
45
  int tlen = len;
dengyihao's avatar
dengyihao 已提交
46
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
47
    int32_t cap = ctx->file.wBufCap;
dengyihao's avatar
dengyihao 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    if (len + ctx->file.wBufOffset >= cap) {
      int32_t nw = cap - ctx->file.wBufOffset;
      memcpy(ctx->file.wBuf + ctx->file.wBufOffset, buf, nw);
      taosWriteFile(ctx->file.pFile, ctx->file.wBuf, cap);

      memset(ctx->file.wBuf, 0, cap);
      ctx->file.wBufOffset = 0;

      len -= nw;
      buf += nw;

      nw = (len / cap) * cap;
      if (nw != 0) {
        taosWriteFile(ctx->file.pFile, buf, nw);
      }

      len -= nw;
      buf += nw;
      if (len != 0) {
        memcpy(ctx->file.wBuf, buf, len);
      }
      ctx->file.wBufOffset += len;
    } else {
      memcpy(ctx->file.wBuf + ctx->file.wBufOffset, buf, len);
      ctx->file.wBufOffset += len;
    }

dengyihao's avatar
dengyihao 已提交
75
  } else {
76 77
    memcpy(ctx->mem.buf + ctx->offset, buf, len);
  }
dengyihao's avatar
dengyihao 已提交
78 79
  ctx->offset += tlen;
  return tlen;
dengyihao's avatar
dengyihao 已提交
80
}
dengyihao's avatar
dengyihao 已提交
81
static FORCE_INLINE int idxFileCtxDoRead(IFileCtx* ctx, uint8_t* buf, int len) {
82
  int nRead = 0;
dengyihao's avatar
dengyihao 已提交
83
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
84 85 86 87
#ifdef USE_MMAP
    nRead = len < ctx->file.size ? len : ctx->file.size;
    memcpy(buf, ctx->file.ptr, nRead);
#else
88
    nRead = taosReadFile(ctx->file.pFile, buf, len);
dengyihao's avatar
dengyihao 已提交
89
#endif
dengyihao's avatar
dengyihao 已提交
90
  } else {
dengyihao's avatar
dengyihao 已提交
91
    memcpy(buf, ctx->mem.buf + ctx->offset, len);
dengyihao's avatar
dengyihao 已提交
92
  }
dengyihao's avatar
dengyihao 已提交
93
  ctx->offset += nRead;
dengyihao's avatar
dengyihao 已提交
94

dengyihao's avatar
dengyihao 已提交
95
  return nRead;
96
}
dengyihao's avatar
dengyihao 已提交
97
static int idxFileCtxDoReadFrom(IFileCtx* ctx, uint8_t* buf, int len, int32_t offset) {
dengyihao's avatar
dengyihao 已提交
98 99 100 101 102
  int32_t total = 0, nread = 0;
  int32_t blkId = offset / kBlockSize;
  int32_t blkOffset = offset % kBlockSize;
  int32_t blkLeft = kBlockSize - blkOffset;

dengyihao's avatar
dengyihao 已提交
103 104
  if (offset >= ctx->file.size) return 0;

dengyihao's avatar
dengyihao 已提交
105
  do {
dengyihao's avatar
dengyihao 已提交
106
    char key[1024] = {0};
dengyihao's avatar
dengyihao 已提交
107
    ASSERT(strlen(ctx->file.buf) + 1 + 64 < sizeof(key));
dengyihao's avatar
dengyihao 已提交
108 109 110 111 112
    idxGenLRUKey(key, ctx->file.buf, blkId);
    LRUHandle* h = taosLRUCacheLookup(ctx->lru, key, strlen(key));

    if (h) {
      SDataBlock* blk = taosLRUCacheValue(ctx->lru, h);
dengyihao's avatar
dengyihao 已提交
113
      nread = TMIN(blkLeft, len);
dengyihao's avatar
dengyihao 已提交
114 115 116
      memcpy(buf + total, blk->buf + blkOffset, nread);
      taosLRUCacheRelease(ctx->lru, h, false);
    } else {
dengyihao's avatar
dengyihao 已提交
117 118 119 120
      int32_t left = ctx->file.size - offset;
      if (left < kBlockSize) {
        nread = TMIN(left, len);
        int32_t bytes = taosPReadFile(ctx->file.pFile, buf + total, nread, offset);
dengyihao's avatar
dengyihao 已提交
121 122
        ASSERTS(bytes == nread, "index read incomplete data");
        if (bytes != nread) break;
dengyihao's avatar
dengyihao 已提交
123 124 125 126 127 128 129 130 131

        total += bytes;
        return total;
      } else {
        int32_t cacheMemSize = sizeof(SDataBlock) + kBlockSize;

        SDataBlock* blk = taosMemoryCalloc(1, cacheMemSize);
        blk->blockId = blkId;
        blk->nread = taosPReadFile(ctx->file.pFile, blk->buf, kBlockSize, blkId * kBlockSize);
dengyihao's avatar
dengyihao 已提交
132
        ASSERTS(blk->nread <= kBlockSize, "index read incomplete data");
dengyihao's avatar
dengyihao 已提交
133
        if (blk->nread < kBlockSize && blk->nread < len) {
dengyihao's avatar
dengyihao 已提交
134
          taosMemoryFree(blk);
dengyihao's avatar
dengyihao 已提交
135 136 137 138 139 140 141
          break;
        }

        nread = TMIN(blkLeft, len);
        memcpy(buf + total, blk->buf + blkOffset, nread);

        LRUStatus s = taosLRUCacheInsert(ctx->lru, key, strlen(key), blk, cacheMemSize, deleteDataBlockFromLRU, NULL,
D
dapan1121 已提交
142
                                         TAOS_LRU_PRIORITY_LOW, NULL);
dengyihao's avatar
dengyihao 已提交
143 144 145
        if (s != TAOS_LRU_STATUS_OK) {
          return -1;
        }
dengyihao's avatar
dengyihao 已提交
146 147 148 149 150 151 152 153 154 155 156 157
      }
    }
    total += nread;
    len -= nread;
    offset += nread;

    blkId = offset / kBlockSize;
    blkOffset = offset % kBlockSize;
    blkLeft = kBlockSize - blkOffset;

  } while (len > 0);
  return total;
dengyihao's avatar
dengyihao 已提交
158
}
dengyihao's avatar
dengyihao 已提交
159
static FORCE_INLINE int idxFileCtxGetSize(IFileCtx* ctx) {
dengyihao's avatar
dengyihao 已提交
160
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
161 162 163 164 165 166 167
    if (ctx->file.readOnly == false) {
      return ctx->offset;
    } else {
      int64_t file_size = 0;
      taosStatFile(ctx->file.buf, &file_size, NULL);
      return (int)file_size;
    }
dengyihao's avatar
dengyihao 已提交
168 169 170
  }
  return 0;
}
dengyihao's avatar
dengyihao 已提交
171
static FORCE_INLINE int idxFileCtxDoFlush(IFileCtx* ctx) {
dengyihao's avatar
dengyihao 已提交
172
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
173 174 175 176
    if (ctx->file.wBufOffset > 0) {
      int32_t nw = taosWriteFile(ctx->file.pFile, ctx->file.wBuf, ctx->file.wBufOffset);
      ctx->file.wBufOffset = 0;
    }
dengyihao's avatar
dengyihao 已提交
177 178
    int ret = taosFsyncFile(ctx->file.pFile);
    UNUSED(ret);
dengyihao's avatar
dengyihao 已提交
179 180 181 182 183 184
  } else {
    // do nothing
  }
  return 1;
}

dengyihao's avatar
dengyihao 已提交
185
IFileCtx* idxFileCtxCreate(WriterType type, const char* path, bool readOnly, int32_t capacity) {
dengyihao's avatar
dengyihao 已提交
186
  int       code = 0;
dengyihao's avatar
dengyihao 已提交
187
  IFileCtx* ctx = taosMemoryCalloc(1, sizeof(IFileCtx));
dengyihao's avatar
dengyihao 已提交
188 189 190
  if (ctx == NULL) {
    return NULL;
  }
dengyihao's avatar
dengyihao 已提交
191
  ctx->type = type;
dengyihao's avatar
dengyihao 已提交
192
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
193
    // ugly code, refactor later
dengyihao's avatar
dengyihao 已提交
194
    ctx->file.readOnly = readOnly;
dengyihao's avatar
dengyihao 已提交
195
    memcpy(ctx->file.buf, path, strlen(path));
dengyihao's avatar
dengyihao 已提交
196
    if (readOnly == false) {
197
      ctx->file.pFile = taosOpenFile(path, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
dengyihao's avatar
dengyihao 已提交
198 199 200 201 202 203

      code = taosFtruncateFile(ctx->file.pFile, 0);
      UNUSED(code);

      code = taosStatFile(path, &ctx->file.size, NULL);
      UNUSED(code);
dengyihao's avatar
dengyihao 已提交
204 205

      ctx->file.wBufOffset = 0;
dengyihao's avatar
dengyihao 已提交
206 207
      ctx->file.wBufCap = kBlockSize * 4;
      ctx->file.wBuf = taosMemoryCalloc(1, ctx->file.wBufCap);
dengyihao's avatar
dengyihao 已提交
208
    } else {
209
      ctx->file.pFile = taosOpenFile(path, TD_FILE_READ);
dengyihao's avatar
dengyihao 已提交
210 211 212
      code = taosFStatFile(ctx->file.pFile, &ctx->file.size, NULL);
      UNUSED(code);

dengyihao's avatar
dengyihao 已提交
213 214
      ctx->file.wBufOffset = 0;

dengyihao's avatar
dengyihao 已提交
215
#ifdef USE_MMAP
216
      ctx->file.ptr = (char*)tfMmapReadOnly(ctx->file.pFile, ctx->file.size);
dengyihao's avatar
dengyihao 已提交
217
#endif
218
    }
219
    if (ctx->file.pFile == NULL) {
dengyihao's avatar
dengyihao 已提交
220
      indexError("failed to open file, error %d", errno);
dengyihao's avatar
dengyihao 已提交
221
      goto END;
dengyihao's avatar
dengyihao 已提交
222
    }
dengyihao's avatar
dengyihao 已提交
223
  } else if (ctx->type == TMEMORY) {
wafwerar's avatar
wafwerar 已提交
224
    ctx->mem.buf = taosMemoryCalloc(1, sizeof(char) * capacity);
dengyihao's avatar
dengyihao 已提交
225
    ctx->mem.cap = capacity;
226
  }
dengyihao's avatar
dengyihao 已提交
227

dengyihao's avatar
dengyihao 已提交
228 229 230 231
  ctx->write = idxFileCtxDoWrite;
  ctx->read = idxFileCtxDoRead;
  ctx->flush = idxFileCtxDoFlush;
  ctx->readFrom = idxFileCtxDoReadFrom;
dengyihao's avatar
dengyihao 已提交
232
  ctx->size = idxFileCtxGetSize;
dengyihao's avatar
dengyihao 已提交
233 234

  ctx->offset = 0;
235
  ctx->limit = capacity;
dengyihao's avatar
dengyihao 已提交
236 237

  return ctx;
dengyihao's avatar
dengyihao 已提交
238
END:
dengyihao's avatar
dengyihao 已提交
239
  if (ctx->type == TMEMORY) {
dengyihao's avatar
dengyihao 已提交
240 241
    taosMemoryFree(ctx->mem.buf);
  }
wafwerar's avatar
wafwerar 已提交
242
  taosMemoryFree(ctx);
dengyihao's avatar
dengyihao 已提交
243
  return NULL;
dengyihao's avatar
dengyihao 已提交
244
}
dengyihao's avatar
dengyihao 已提交
245
void idxFileCtxDestroy(IFileCtx* ctx, bool remove) {
dengyihao's avatar
dengyihao 已提交
246
  if (ctx->type == TMEMORY) {
wafwerar's avatar
wafwerar 已提交
247
    taosMemoryFree(ctx->mem.buf);
dengyihao's avatar
dengyihao 已提交
248
  } else {
dengyihao's avatar
dengyihao 已提交
249 250 251 252
    if (ctx->file.wBufOffset > 0) {
      int32_t nw = taosWriteFile(ctx->file.pFile, ctx->file.wBuf, ctx->file.wBufOffset);
      ctx->file.wBufOffset = 0;
    }
dengyihao's avatar
dengyihao 已提交
253
    ctx->flush(ctx);
dengyihao's avatar
dengyihao 已提交
254
    taosMemoryFreeClear(ctx->file.wBuf);
255
    taosCloseFile(&ctx->file.pFile);
dengyihao's avatar
dengyihao 已提交
256 257 258 259 260
    if (ctx->file.readOnly) {
#ifdef USE_MMAP
      munmap(ctx->file.ptr, ctx->file.size);
#endif
    }
dengyihao's avatar
dengyihao 已提交
261 262 263
    if (remove) {
      unlink(ctx->file.buf);
    }
dengyihao's avatar
dengyihao 已提交
264
  }
wafwerar's avatar
wafwerar 已提交
265
  taosMemoryFree(ctx);
dengyihao's avatar
dengyihao 已提交
266 267
}

dengyihao's avatar
dengyihao 已提交
268 269
IdxFstFile* idxFileCreate(void* wrt) {
  IdxFstFile* cw = taosMemoryCalloc(1, sizeof(IdxFstFile));
dengyihao's avatar
dengyihao 已提交
270 271 272
  if (cw == NULL) {
    return NULL;
  }
273

dengyihao's avatar
dengyihao 已提交
274
  cw->wrt = wrt;
275
  return cw;
dengyihao's avatar
dengyihao 已提交
276
}
dengyihao's avatar
dengyihao 已提交
277 278
void idxFileDestroy(IdxFstFile* cw) {
  idxFileFlush(cw);
wafwerar's avatar
wafwerar 已提交
279
  taosMemoryFree(cw);
dengyihao's avatar
dengyihao 已提交
280 281
}

dengyihao's avatar
dengyihao 已提交
282
int idxFileWrite(IdxFstFile* write, uint8_t* buf, uint32_t len) {
dengyihao's avatar
dengyihao 已提交
283 284 285
  if (write == NULL) {
    return 0;
  }
286
  // update checksum
dengyihao's avatar
dengyihao 已提交
287
  IFileCtx* ctx = write->wrt;
dengyihao's avatar
dengyihao 已提交
288
  int       nWrite = ctx->write(ctx, buf, len);
dengyihao's avatar
dengyihao 已提交
289 290 291 292
  ASSERTS(nWrite == len, "index write incomplete data");
  if (nWrite != len) {
    return -1;
  }
dengyihao's avatar
dengyihao 已提交
293
  write->count += len;
dengyihao's avatar
dengyihao 已提交
294 295

  write->summer = taosCalcChecksum(write->summer, buf, len);
296 297
  return len;
}
dengyihao's avatar
dengyihao 已提交
298

dengyihao's avatar
dengyihao 已提交
299
int idxFileRead(IdxFstFile* write, uint8_t* buf, uint32_t len) {
dengyihao's avatar
dengyihao 已提交
300 301 302
  if (write == NULL) {
    return 0;
  }
dengyihao's avatar
dengyihao 已提交
303
  IFileCtx* ctx = write->wrt;
dengyihao's avatar
dengyihao 已提交
304
  return ctx->read(ctx, buf, len);
dengyihao's avatar
dengyihao 已提交
305
}
306

dengyihao's avatar
dengyihao 已提交
307
uint32_t idxFileMaskedCheckSum(IdxFstFile* write) {
dengyihao's avatar
dengyihao 已提交
308
  //////
dengyihao's avatar
dengyihao 已提交
309 310
  return write->summer;
}
dengyihao's avatar
dengyihao 已提交
311

dengyihao's avatar
dengyihao 已提交
312 313
int idxFileFlush(IdxFstFile* write) {
  IFileCtx* ctx = write->wrt;
dengyihao's avatar
dengyihao 已提交
314
  ctx->flush(ctx);
dengyihao's avatar
dengyihao 已提交
315 316 317
  return 1;
}

dengyihao's avatar
dengyihao 已提交
318
void idxFilePackUintIn(IdxFstFile* writer, uint64_t n, uint8_t nBytes) {
wafwerar's avatar
wafwerar 已提交
319
  uint8_t* buf = taosMemoryCalloc(8, sizeof(uint8_t));
dengyihao's avatar
dengyihao 已提交
320
  for (uint8_t i = 0; i < nBytes; i++) {
321
    buf[i] = (uint8_t)n;
dengyihao's avatar
dengyihao 已提交
322 323
    n = n >> 8;
  }
dengyihao's avatar
dengyihao 已提交
324
  idxFileWrite(writer, buf, nBytes);
wafwerar's avatar
wafwerar 已提交
325
  taosMemoryFree(buf);
dengyihao's avatar
dengyihao 已提交
326 327
  return;
}
dengyihao's avatar
dengyihao 已提交
328

dengyihao's avatar
dengyihao 已提交
329
uint8_t idxFilePackUint(IdxFstFile* writer, uint64_t n) {
dengyihao's avatar
dengyihao 已提交
330
  uint8_t nBytes = packSize(n);
dengyihao's avatar
dengyihao 已提交
331
  idxFilePackUintIn(writer, n, nBytes);
332 333
  return nBytes;
}