tsdbFS.c 14.7 KB
Newer Older
H
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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/>.
H
Hongze Cheng 已提交
14 15
 */

H
Hongze Cheng 已提交
16
#include "inc/tsdbFS.h"
H
Hongze Cheng 已提交
17

H
Hongze Cheng 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30
#define TSDB_FS_EDIT_MIN TSDB_FS_EDIT_COMMIT
#define TSDB_FS_EDIT_MAX (TSDB_FS_EDIT_MERGE + 1)

enum {
  TSDB_FS_STATE_NONE = 0,
  TSDB_FS_STATE_OPEN,
  TSDB_FS_STATE_EDIT,
  TSDB_FS_STATE_CLOSE,
};

static int32_t create_file_system(STsdb *pTsdb, STFileSystem **ppFS) {
  ppFS[0] = taosMemoryCalloc(1, sizeof(*ppFS[0]));
  if (ppFS[0] == NULL) {
H
Hongze Cheng 已提交
31 32 33
    return TSDB_CODE_OUT_OF_MEMORY;
  }

H
Hongze Cheng 已提交
34 35 36 37 38
  ppFS[0]->cstate = taosArrayInit(16, sizeof(STFileSet));
  ppFS[0]->nstate = taosArrayInit(16, sizeof(STFileSet));
  if (ppFS[0]->cstate == NULL || ppFS[0]->nstate == NULL) {
    taosArrayDestroy(ppFS[0]->nstate);
    taosArrayDestroy(ppFS[0]->cstate);
H
Hongze Cheng 已提交
39 40 41
    taosMemoryFree(ppFS[0]);
    return TSDB_CODE_OUT_OF_MEMORY;
  }
H
Hongze Cheng 已提交
42

H
Hongze Cheng 已提交
43
  ppFS[0]->pTsdb = pTsdb;
H
Hongze Cheng 已提交
44
  ppFS[0]->state = TSDB_FS_STATE_NONE;
H
Hongze Cheng 已提交
45
  tsem_init(&ppFS[0]->canEdit, 0, 1);
H
Hongze Cheng 已提交
46
  ppFS[0]->nextEditId = 0;
H
Hongze Cheng 已提交
47

H
Hongze Cheng 已提交
48 49 50
  return 0;
}

H
Hongze Cheng 已提交
51
static int32_t destroy_file_system(STFileSystem **ppFS) {
H
Hongze Cheng 已提交
52
  if (ppFS[0]) {
H
Hongze Cheng 已提交
53 54
    taosArrayDestroy(ppFS[0]->nstate);
    taosArrayDestroy(ppFS[0]->cstate);
H
Hongze Cheng 已提交
55
    tsem_destroy(&ppFS[0]->canEdit);
H
Hongze Cheng 已提交
56 57 58 59 60 61
    taosMemoryFree(ppFS[0]);
    ppFS[0] = NULL;
  }
  return 0;
}

H
Hongze Cheng 已提交
62
static int32_t get_current_json(STsdb *pTsdb, char fname[]) {
H
Hongze Cheng 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
  if (pTsdb->pVnode->pTfs) {
    snprintf(fname,                                   //
             TSDB_FILENAME_LEN,                       //
             "%s%s%s%s%s",                            //
             tfsGetPrimaryPath(pTsdb->pVnode->pTfs),  //
             TD_DIRSEP,                               //
             pTsdb->path,                             //
             TD_DIRSEP,                               //
             "current.json");
  } else {
    snprintf(fname,              //
             TSDB_FILENAME_LEN,  //
             "%s%s%s",           //
             pTsdb->path,        //
             TD_DIRSEP,          //
             "current.json");
  }
H
Hongze Cheng 已提交
80
  return 0;
H
Hongze Cheng 已提交
81 82
}

H
Hongze Cheng 已提交
83
static int32_t get_current_temp(STsdb *pTsdb, char fname[], tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
84 85
  switch (etype) {
    case TSDB_FS_EDIT_COMMIT:
H
Hongze Cheng 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
      if (pTsdb->pVnode->pTfs) {
        snprintf(fname,                                   //
                 TSDB_FILENAME_LEN,                       //
                 "%s%s%s%s%s",                            //
                 tfsGetPrimaryPath(pTsdb->pVnode->pTfs),  //
                 TD_DIRSEP,                               //
                 pTsdb->path,                             //
                 TD_DIRSEP,                               //
                 "current.json.commit");
      } else {
        snprintf(fname,              //
                 TSDB_FILENAME_LEN,  //
                 "%s%s%s",           //
                 pTsdb->path,        //
                 TD_DIRSEP,          //
                 "current.json.commit");
      }
H
Hongze Cheng 已提交
103 104
      break;
    default:
H
Hongze Cheng 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
      if (pTsdb->pVnode->pTfs) {
        snprintf(fname,                                   //
                 TSDB_FILENAME_LEN,                       //
                 "%s%s%s%s%s",                            //
                 tfsGetPrimaryPath(pTsdb->pVnode->pTfs),  //
                 TD_DIRSEP,                               //
                 pTsdb->path,                             //
                 TD_DIRSEP,                               //
                 "current.json.t");
      } else {
        snprintf(fname,              //
                 TSDB_FILENAME_LEN,  //
                 "%s%s%s",           //
                 pTsdb->path,        //
                 TD_DIRSEP,          //
                 "current.json.t");
      }
H
Hongze Cheng 已提交
122 123 124 125 126 127
      break;
  }

  return 0;
}

H
Hongze Cheng 已提交
128
static int32_t fs_to_json_str(STFileSystem *pFS, char **ppData) {
H
Hongze Cheng 已提交
129 130 131 132 133 134 135 136 137
  int32_t code = 0;
  int32_t lino;

  cJSON *pJson = cJSON_CreateObject();
  if (pJson == NULL) {
    return TSDB_CODE_OUT_OF_MEMORY;
  }

  /* format version */
H
Hongze Cheng 已提交
138 139 140
  TSDB_CHECK_NULL(                        //
      cJSON_AddNumberToObject(pJson,      //
                              "version",  //
H
Hongze Cheng 已提交
141 142 143 144 145 146 147
                              1 /* TODO */),
      code,   //
      lino,   //
      _exit,  //
      TSDB_CODE_OUT_OF_MEMORY);

  /* next edit id */
H
Hongze Cheng 已提交
148 149 150
  TSDB_CHECK_NULL(                        //
      cJSON_AddNumberToObject(pJson,      //
                              "edit id",  //
H
Hongze Cheng 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
                              pFS->nextEditId),
      code,   //
      lino,   //
      _exit,  //
      TSDB_CODE_OUT_OF_MEMORY);

  /* file sets */
  cJSON *aFileSetJson;
  TSDB_CHECK_NULL(                                                //
      aFileSetJson = cJSON_AddArrayToObject(pJson, "file sets"),  //
      code,                                                       //
      lino,                                                       //
      _exit,                                                      //
      TSDB_CODE_OUT_OF_MEMORY);

H
Hongze Cheng 已提交
166 167
  for (int32_t i = 0; i < taosArrayGetSize(pFS->nstate); i++) {
    struct STFileSet *pFileSet = taosArrayGet(pFS->nstate, i);
H
Hongze Cheng 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190

    code = tsdbFileSetToJson(aFileSetJson, pFileSet);
    TSDB_CHECK_CODE(code, lino, _exit);
  }

  ppData[0] = cJSON_Print(pJson);
  if (ppData[0] == NULL) {
    code = TSDB_CODE_OUT_OF_MEMORY;
    TSDB_CHECK_CODE(code, lino, _exit);
  }

_exit:
  cJSON_Delete(pJson);
  if (code) {
    tsdbError("vgId:%d %s failed at line %d since %s",  //
              TD_VID(pFS->pTsdb->pVnode),               //
              __func__,                                 //
              lino,                                     //
              tstrerror(code));
  }
  return code;
}

H
Hongze Cheng 已提交
191
static int32_t fs_from_json_str(const char *pData, STFileSystem *pFS) {
H
Hongze Cheng 已提交
192 193 194
  int32_t code = 0;
  int32_t lino;

H
Hongze Cheng 已提交
195
  ASSERTS(0, "TODO: Not implemented yet");
H
Hongze Cheng 已提交
196 197 198 199 200

_exit:
  return code;
}

H
Hongze Cheng 已提交
201
static int32_t save_fs_to_file(STFileSystem *pFS, const char *fname) {
H
Hongze Cheng 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  int32_t code = 0;
  int32_t lino;
  char   *pData = NULL;

  // to json string
  code = fs_to_json_str(pFS, &pData);
  TSDB_CHECK_CODE(code, lino, _exit);

  TdFilePtr fd = taosOpenFile(fname,                //
                              TD_FILE_WRITE         //
                                  | TD_FILE_CREATE  //
                                  | TD_FILE_TRUNC);
  if (fd == NULL) {
    code = TAOS_SYSTEM_ERROR(code);
    TSDB_CHECK_CODE(code, lino, _exit);
  }

  int64_t n = taosWriteFile(fd, pData, strlen(pData) + 1);
  if (n < 0) {
    code = TAOS_SYSTEM_ERROR(code);
    taosCloseFile(&fd);
    TSDB_CHECK_CODE(code, lino, _exit);
  }

  if (taosFsyncFile(fd) < 0) {
    code = TAOS_SYSTEM_ERROR(code);
    taosCloseFile(&fd);
    TSDB_CHECK_CODE(code, lino, _exit);
  }

  taosCloseFile(&fd);

_exit:
  if (code) {
    tsdbError("vgId:%d %s failed at line %d since %s",  //
              TD_VID(pFS->pTsdb->pVnode),               //
              __func__,                                 //
              lino,                                     //
              tstrerror(code));
  } else {
    tsdbDebug("vgId:%d %s success",        //
              TD_VID(pFS->pTsdb->pVnode),  //
              __func__);
  }
  if (pData) {
    taosMemoryFree(pData);
  }
  return code;
H
Hongze Cheng 已提交
250 251
}

H
Hongze Cheng 已提交
252
static int32_t load_fs_from_file(const char *fname, STFileSystem *pFS) {
H
Hongze Cheng 已提交
253 254 255 256
  ASSERTS(0, "TODO: Not implemented yet");
  return 0;
}

H
Hongze Cheng 已提交
257
static int32_t commit_edit(STFileSystem *pFS, tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
  int32_t code;
  char    ofname[TSDB_FILENAME_LEN];
  char    nfname[TSDB_FILENAME_LEN];

  get_current_json(pFS->pTsdb, nfname);
  get_current_temp(pFS->pTsdb, ofname, etype);

  code = taosRenameFile(ofname, nfname);
  if (code) {
    code = TAOS_SYSTEM_ERROR(code);
    return code;
  }

  ASSERTS(0, "TODO: Do changes to pFS");

H
Hongze Cheng 已提交
273 274 275
  return 0;
}

H
Hongze Cheng 已提交
276
static int32_t abort_edit(STFileSystem *pFS, tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
277 278 279 280 281 282 283 284 285 286 287
  int32_t code;
  char    fname[TSDB_FILENAME_LEN];

  get_current_temp(pFS->pTsdb, fname, etype);

  code = taosRemoveFile(fname);
  if (code) code = TAOS_SYSTEM_ERROR(code);

  return code;
}

H
Hongze Cheng 已提交
288
static int32_t scan_file_system(STFileSystem *pFS) {
H
Hongze Cheng 已提交
289 290 291 292
  // ASSERTS(0, "TODO: Not implemented yet");
  return 0;
}

H
Hongze Cheng 已提交
293
static int32_t scan_and_schedule_merge(STFileSystem *pFS) {
H
Hongze Cheng 已提交
294
  // ASSERTS(0, "TODO: Not implemented yet");
H
Hongze Cheng 已提交
295 296 297
  return 0;
}

H
Hongze Cheng 已提交
298
static int32_t open_file_system(STFileSystem *pFS, int8_t rollback) {
H
Hongze Cheng 已提交
299
  int32_t code = 0;
H
Hongze Cheng 已提交
300
  int32_t lino = 0;
H
Hongze Cheng 已提交
301 302
  STsdb  *pTsdb = pFS->pTsdb;

H
Hongze Cheng 已提交
303 304 305
  bool update = false;  // TODO
  if (update) {
    // TODO
H
Hongze Cheng 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
  } else {
    char current_json[TSDB_FILENAME_LEN];
    char current_json_commit[TSDB_FILENAME_LEN];
    char current_json_t[TSDB_FILENAME_LEN];

    get_current_json(pTsdb, current_json);
    get_current_temp(pTsdb, current_json_commit, TSDB_FS_EDIT_COMMIT);
    get_current_temp(pTsdb, current_json_t, TSDB_FS_EDIT_MERGE);

    if (taosCheckExistFile(current_json)) {  // current.json exists
      code = load_fs_from_file(current_json, pFS);
      TSDB_CHECK_CODE(code, lino, _exit);

      // check current.json.commit existence
      if (taosCheckExistFile(current_json_commit)) {
        if (rollback) {
          code = commit_edit(pFS, TSDB_FS_EDIT_COMMIT);
          TSDB_CHECK_CODE(code, lino, _exit);
        } else {
          code = abort_edit(pFS, TSDB_FS_EDIT_COMMIT);
          TSDB_CHECK_CODE(code, lino, _exit);
        }
      }

      // check current.json.t existence
      if (taosCheckExistFile(current_json_t)) {
        code = abort_edit(pFS, TSDB_FS_EDIT_MERGE);
        TSDB_CHECK_CODE(code, lino, _exit);
      }
    } else {
      code = save_fs_to_file(pFS, current_json);
      TSDB_CHECK_CODE(code, lino, _exit);
    }
  }

H
Hongze Cheng 已提交
341 342 343 344 345 346
  code = scan_file_system(pFS);
  TSDB_CHECK_CODE(code, lino, _exit);

  code = scan_and_schedule_merge(pFS);
  TSDB_CHECK_CODE(code, lino, _exit);

H
Hongze Cheng 已提交
347 348
_exit:
  if (code) {
H
Hongze Cheng 已提交
349
    tsdbError("vgId:%d %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
H
Hongze Cheng 已提交
350
  } else {
H
Hongze Cheng 已提交
351
    tsdbInfo("vgId:%d %s success", TD_VID(pTsdb->pVnode), __func__);
H
Hongze Cheng 已提交
352
  }
H
Hongze Cheng 已提交
353 354 355
  return 0;
}

H
Hongze Cheng 已提交
356
static int32_t close_file_system(STFileSystem *pFS) {
H
Hongze Cheng 已提交
357
  ASSERTS(0, "TODO: Not implemented yet");
H
Hongze Cheng 已提交
358 359
  return 0;
}
H
Hongze Cheng 已提交
360

H
Hongze Cheng 已提交
361
static int32_t apply_edit(STFileSystem *pFS) {
H
Hongze Cheng 已提交
362
  int32_t code = 0;
H
Hongze Cheng 已提交
363
  ASSERTS(0, "TODO: Not implemented yet");
H
Hongze Cheng 已提交
364
  return code;
H
Hongze Cheng 已提交
365 366
}

H
Hongze Cheng 已提交
367
static int32_t fset_cmpr_fn(const struct STFileSet *pSet1, const struct STFileSet *pSet2) {
H
Hongze Cheng 已提交
368 369 370 371 372 373 374 375
  if (pSet1->fid < pSet2->fid) {
    return -1;
  } else if (pSet1->fid > pSet2->fid) {
    return 1;
  }
  return 0;
}

H
Hongze Cheng 已提交
376
static int32_t edit_fs(STFileSystem *pFS, const SArray *aFileOp) {
H
Hongze Cheng 已提交
377 378 379
  int32_t code = 0;
  int32_t lino;

H
Hongze Cheng 已提交
380
  taosArrayClearEx(pFS->nstate, NULL /* TODO */);
H
Hongze Cheng 已提交
381 382 383

  // TODO: copy current state to new state

H
Hongze Cheng 已提交
384 385
  for (int32_t iop = 0; iop < taosArrayGetSize(aFileOp); iop++) {
    struct SFileOp *pOp = taosArrayGet(aFileOp, iop);
H
Hongze Cheng 已提交
386

H
Hongze Cheng 已提交
387
    struct STFileSet tmpSet = {.fid = pOp->fid};
H
Hongze Cheng 已提交
388 389

    int32_t idx = taosArraySearchIdx(  //
H
Hongze Cheng 已提交
390
        pFS->nstate,                   //
H
Hongze Cheng 已提交
391 392 393 394
        &tmpSet,                       //
        (__compar_fn_t)fset_cmpr_fn,   //
        TD_GE);

H
Hongze Cheng 已提交
395
    struct STFileSet *pSet;
H
Hongze Cheng 已提交
396 397
    if (idx < 0) {
      pSet = NULL;
H
Hongze Cheng 已提交
398
      idx = taosArrayGetSize(pFS->nstate);
H
Hongze Cheng 已提交
399
    } else {
H
Hongze Cheng 已提交
400
      pSet = taosArrayGet(pFS->nstate, idx);
H
Hongze Cheng 已提交
401 402 403 404 405 406 407 408 409
    }

    if (pSet == NULL || pSet->fid != pOp->fid) {
      ASSERTS(pOp->op == TSDB_FOP_CREATE, "BUG: Invalid file operation");
      TSDB_CHECK_CODE(                                //
          code = tsdbFileSetCreate(pOp->fid, &pSet),  //
          lino,                                       //
          _exit);

H
Hongze Cheng 已提交
410
      if (taosArrayInsert(pFS->nstate, idx, pSet) == NULL) {
H
Hongze Cheng 已提交
411 412 413 414 415 416
        code = TSDB_CODE_OUT_OF_MEMORY;
        TSDB_CHECK_CODE(code, lino, _exit);
      }
    }

    // do opration on file set
H
Hongze Cheng 已提交
417
    TSDB_CHECK_CODE(                        //
H
Hongze Cheng 已提交
418
        code = tsdbFileSetEdit(pSet, pOp),  //
H
Hongze Cheng 已提交
419 420
        lino,                               //
        _exit);
H
Hongze Cheng 已提交
421 422
  }

H
Hongze Cheng 已提交
423 424
  // TODO: write new state to file

H
Hongze Cheng 已提交
425
_exit:
H
Hongze Cheng 已提交
426 427 428
  return 0;
}

H
Hongze Cheng 已提交
429
int32_t tsdbOpenFileSystem(STsdb *pTsdb, STFileSystem **ppFS, int8_t rollback) {
H
Hongze Cheng 已提交
430 431 432 433 434 435
  int32_t code;
  int32_t lino;

  code = create_file_system(pTsdb, ppFS);
  TSDB_CHECK_CODE(code, lino, _exit);

H
Hongze Cheng 已提交
436
  code = open_file_system(ppFS[0], rollback);
H
Hongze Cheng 已提交
437
  TSDB_CHECK_CODE(code, lino, _exit)
H
Hongze Cheng 已提交
438 439 440

_exit:
  if (code) {
H
Hongze Cheng 已提交
441 442
    tsdbError("vgId:%d %s failed at line %d since %s", TD_VID(pTsdb->pVnode), __func__, lino, tstrerror(code));
    destroy_file_system(ppFS);
H
Hongze Cheng 已提交
443
  } else {
H
Hongze Cheng 已提交
444
    tsdbInfo("vgId:%d %s success", TD_VID(pTsdb->pVnode), __func__);
H
Hongze Cheng 已提交
445 446 447 448
  }
  return 0;
}

H
Hongze Cheng 已提交
449
int32_t tsdbCloseFileSystem(STFileSystem **ppFS) {
H
Hongze Cheng 已提交
450 451 452 453 454
  if (ppFS[0] == NULL) return 0;
  close_file_system(ppFS[0]);
  destroy_file_system(ppFS);
  return 0;
}
H
Hongze Cheng 已提交
455

H
Hongze Cheng 已提交
456
int32_t tsdbFileSystemEditBegin(STFileSystem *pFS, const SArray *aFileOp, tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
457
  int32_t code = 0;
H
Hongze Cheng 已提交
458
  int32_t lino;
H
Hongze Cheng 已提交
459 460
  char    fname[TSDB_FILENAME_LEN];

H
Hongze Cheng 已提交
461
  get_current_temp(pFS->pTsdb, fname, etype);
H
Hongze Cheng 已提交
462

H
Hongze Cheng 已提交
463
  tsem_wait(&pFS->canEdit);
H
Hongze Cheng 已提交
464

H
Hongze Cheng 已提交
465 466 467 468 469 470 471 472 473
  TSDB_CHECK_CODE(                   //
      code = edit_fs(pFS, aFileOp),  //
      lino,                          //
      _exit);

  TSDB_CHECK_CODE(                         //
      code = save_fs_to_file(pFS, fname),  //
      lino,                                //
      _exit);
H
Hongze Cheng 已提交
474 475 476 477 478 479 480 481

_exit:
  if (code) {
    tsdbError("vgId:%d %s failed at line %d since %s",  //
              TD_VID(pFS->pTsdb->pVnode),               //
              __func__,                                 //
              lino,                                     //
              tstrerror(code));
H
Hongze Cheng 已提交
482 483 484 485 486
  } else {
    tsdbInfo("vgId:%d %s done, etype:%d",  //
             TD_VID(pFS->pTsdb->pVnode),   //
             __func__,                     //
             etype);
H
Hongze Cheng 已提交
487 488 489 490
  }
  return code;
}

H
Hongze Cheng 已提交
491
int32_t tsdbFileSystemEditCommit(STFileSystem *pFS, tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
492
  int32_t code = commit_edit(pFS, etype);
H
Hongze Cheng 已提交
493
  tsem_post(&pFS->canEdit);
H
Hongze Cheng 已提交
494
  if (code) {
H
Hongze Cheng 已提交
495 496 497
    tsdbError("vgId:%d %s failed since %s",  //
              TD_VID(pFS->pTsdb->pVnode),    //
              __func__,                      //
H
Hongze Cheng 已提交
498
              tstrerror(code));
H
Hongze Cheng 已提交
499 500 501 502 503
  } else {
    tsdbInfo("vgId:%d %s done, etype:%d",  //
             TD_VID(pFS->pTsdb->pVnode),   //
             __func__,                     //
             etype);
H
Hongze Cheng 已提交
504 505 506 507
  }
  return code;
}

H
Hongze Cheng 已提交
508
int32_t tsdbFileSystemEditAbort(STFileSystem *pFS, tsdb_fs_edit_t etype) {
H
Hongze Cheng 已提交
509
  int32_t code = abort_edit(pFS, etype);
H
Hongze Cheng 已提交
510
  if (code) {
H
Hongze Cheng 已提交
511 512 513 514 515
    tsdbError("vgId:%d %s failed since %s, etype:%d",  //
              TD_VID(pFS->pTsdb->pVnode),              //
              __func__,                                //
              tstrerror(code),                         //
              etype);
H
Hongze Cheng 已提交
516
  } else {
H
Hongze Cheng 已提交
517
  }
H
Hongze Cheng 已提交
518
  tsem_post(&pFS->canEdit);
H
Hongze Cheng 已提交
519 520
  return code;
}