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 32 33
static int32_t kBlockSize = 4096;

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

static void deleteDataBlockFromLRU(const void* key, size_t keyLen, void* value) { taosMemoryFree(value); }

dengyihao's avatar
dengyihao 已提交
34
static FORCE_INLINE void idxGenLRUKey(char* buf, const char* path, int32_t blockId) {
dengyihao's avatar
dengyihao 已提交
35 36 37 38 39 40
  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 已提交
41
static FORCE_INLINE int idxFileCtxDoWrite(IFileCtx* ctx, uint8_t* buf, int len) {
dengyihao's avatar
dengyihao 已提交
42
  int tlen = len;
dengyihao's avatar
dengyihao 已提交
43
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
44
    int32_t cap = ctx->file.wBufCap;
dengyihao's avatar
dengyihao 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    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 已提交
72
  } else {
73 74
    memcpy(ctx->mem.buf + ctx->offset, buf, len);
  }
dengyihao's avatar
dengyihao 已提交
75 76
  ctx->offset += tlen;
  return tlen;
dengyihao's avatar
dengyihao 已提交
77
}
dengyihao's avatar
dengyihao 已提交
78
static FORCE_INLINE int idxFileCtxDoRead(IFileCtx* ctx, uint8_t* buf, int len) {
79
  int nRead = 0;
dengyihao's avatar
dengyihao 已提交
80
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
81 82 83 84
#ifdef USE_MMAP
    nRead = len < ctx->file.size ? len : ctx->file.size;
    memcpy(buf, ctx->file.ptr, nRead);
#else
85
    nRead = taosReadFile(ctx->file.pFile, buf, len);
dengyihao's avatar
dengyihao 已提交
86
#endif
dengyihao's avatar
dengyihao 已提交
87
  } else {
dengyihao's avatar
dengyihao 已提交
88
    memcpy(buf, ctx->mem.buf + ctx->offset, len);
dengyihao's avatar
dengyihao 已提交
89
  }
dengyihao's avatar
dengyihao 已提交
90
  ctx->offset += nRead;
dengyihao's avatar
dengyihao 已提交
91

dengyihao's avatar
dengyihao 已提交
92
  return nRead;
93
}
dengyihao's avatar
dengyihao 已提交
94
static int idxFileCtxDoReadFrom(IFileCtx* ctx, uint8_t* buf, int len, int32_t offset) {
dengyihao's avatar
dengyihao 已提交
95 96 97 98 99
  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 已提交
100 101
  if (offset >= ctx->file.size) return 0;

dengyihao's avatar
dengyihao 已提交
102
  do {
dengyihao's avatar
dengyihao 已提交
103
    char key[1024] = {0};
dengyihao's avatar
dengyihao 已提交
104
    ASSERT(strlen(ctx->file.buf) + 1 + 64 < sizeof(key));
dengyihao's avatar
dengyihao 已提交
105 106 107 108 109
    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 已提交
110
      nread = TMIN(blkLeft, len);
dengyihao's avatar
dengyihao 已提交
111 112 113
      memcpy(buf + total, blk->buf + blkOffset, nread);
      taosLRUCacheRelease(ctx->lru, h, false);
    } else {
dengyihao's avatar
dengyihao 已提交
114 115 116 117
      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 已提交
118 119
        ASSERTS(bytes == nread, "index read incomplete data");
        if (bytes != nread) break;
dengyihao's avatar
dengyihao 已提交
120 121 122 123 124 125 126 127 128

        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 已提交
129 130
        ASSERTS(blk->nread <= kBlockSize, "index read incomplete data");
        if (blk->nread > kBlockSize) break;
dengyihao's avatar
dengyihao 已提交
131 132

        if (blk->nread < kBlockSize && blk->nread < len) {
dengyihao's avatar
dengyihao 已提交
133
          taosMemoryFree(blk);
dengyihao's avatar
dengyihao 已提交
134 135 136 137 138 139 140 141 142 143 144
          break;
        }

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

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

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

  } while (len > 0);
  return total;
dengyihao's avatar
dengyihao 已提交
157
}
dengyihao's avatar
dengyihao 已提交
158
static FORCE_INLINE int idxFileCtxGetSize(IFileCtx* ctx) {
dengyihao's avatar
dengyihao 已提交
159
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
160 161 162 163 164 165 166
    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 已提交
167 168 169
  }
  return 0;
}
dengyihao's avatar
dengyihao 已提交
170
static FORCE_INLINE int idxFileCtxDoFlush(IFileCtx* ctx) {
dengyihao's avatar
dengyihao 已提交
171
  if (ctx->type == TFILE) {
dengyihao's avatar
dengyihao 已提交
172 173 174 175
    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 已提交
176 177
    int ret = taosFsyncFile(ctx->file.pFile);
    UNUSED(ret);
dengyihao's avatar
dengyihao 已提交
178 179 180 181 182 183
  } else {
    // do nothing
  }
  return 1;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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