Coverage Report

Created: 2026-05-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/file/filename.cc
Line
Count
Source
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under both the GPLv2 (found in the
3
//  COPYING file in the root directory) and Apache 2.0 License
4
//  (found in the LICENSE.Apache file in the root directory).
5
//
6
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7
// Use of this source code is governed by a BSD-style license that can be
8
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
#include "file/filename.h"
10
11
#include <cctype>
12
#include <cinttypes>
13
#include <cstdio>
14
#include <vector>
15
16
#include "file/file_util.h"
17
#include "file/writable_file_writer.h"
18
#include "rocksdb/env.h"
19
#include "rocksdb/file_system.h"
20
#include "test_util/sync_point.h"
21
#include "util/stop_watch.h"
22
#include "util/string_util.h"
23
24
namespace ROCKSDB_NAMESPACE {
25
26
const std::string kCurrentFileName = "CURRENT";
27
const std::string kOptionsFileNamePrefix = "OPTIONS-";
28
const std::string kCompactionProgressFileNamePrefix = "COMPACTION_PROGRESS-";
29
const std::string kTempFileNameSuffix = "dbtmp";
30
31
static const std::string kRocksDbTFileExt = "sst";
32
static const std::string kLevelDbTFileExt = "ldb";
33
static const std::string kRocksDBBlobFileExt = "blob";
34
static const std::string kArchivalDirName = "archive";
35
36
// Given a path, flatten the path name by replacing all chars not in
37
// {[0-9,a-z,A-Z,-,_,.]} with _. And append '_LOG\0' at the end.
38
// Return the number of chars stored in dest not including the trailing '\0'.
39
0
static size_t GetInfoLogPrefix(const std::string& path, char* dest, int len) {
40
0
  const char suffix[] = "_LOG";
41
42
0
  size_t write_idx = 0;
43
0
  size_t i = 0;
44
0
  size_t src_len = path.size();
45
46
0
  while (i < src_len && write_idx < len - sizeof(suffix)) {
47
0
    if ((path[i] >= 'a' && path[i] <= 'z') ||
48
0
        (path[i] >= '0' && path[i] <= '9') ||
49
0
        (path[i] >= 'A' && path[i] <= 'Z') || path[i] == '-' ||
50
0
        path[i] == '.' || path[i] == '_') {
51
0
      dest[write_idx++] = path[i];
52
0
    } else {
53
0
      if (i > 0) {
54
0
        dest[write_idx++] = '_';
55
0
      }
56
0
    }
57
0
    i++;
58
0
  }
59
0
  assert(sizeof(suffix) <= len - write_idx);
60
  // "\0" is automatically added by snprintf
61
0
  snprintf(dest + write_idx, len - write_idx, suffix);
62
0
  write_idx += sizeof(suffix) - 1;
63
0
  return write_idx;
64
0
}
65
66
541k
static std::string MakeFileName(uint64_t number, const char* suffix) {
67
541k
  char buf[100];
68
541k
  snprintf(buf, sizeof(buf), "%06llu.%s",
69
541k
           static_cast<unsigned long long>(number), suffix);
70
541k
  return buf;
71
541k
}
72
73
static std::string MakeFileName(const std::string& name, uint64_t number,
74
531k
                                const char* suffix) {
75
531k
  return name + "/" + MakeFileName(number, suffix);
76
531k
}
77
78
178k
std::string LogFileName(const std::string& name, uint64_t number) {
79
178k
  assert(number > 0);
80
178k
  return MakeFileName(name, number, "log");
81
178k
}
82
83
2.09k
std::string LogFileName(uint64_t number) {
84
2.09k
  assert(number > 0);
85
2.09k
  return MakeFileName(number, "log");
86
2.09k
}
87
88
0
std::string BlobFileName(uint64_t number) {
89
0
  assert(number > 0);
90
0
  return MakeFileName(number, kRocksDBBlobFileExt.c_str());
91
0
}
92
93
0
std::string BlobFileName(const std::string& blobdirname, uint64_t number) {
94
0
  assert(number > 0);
95
0
  return MakeFileName(blobdirname, number, kRocksDBBlobFileExt.c_str());
96
0
}
97
98
std::string BlobFileName(const std::string& dbname, const std::string& blob_dir,
99
0
                         uint64_t number) {
100
0
  assert(number > 0);
101
0
  return MakeFileName(dbname + "/" + blob_dir, number,
102
0
                      kRocksDBBlobFileExt.c_str());
103
0
}
104
105
7.64k
std::string ArchivalDirectory(const std::string& dir) {
106
7.64k
  return dir + "/" + kArchivalDirName;
107
7.64k
}
108
0
std::string ArchivedLogFileName(const std::string& name, uint64_t number) {
109
0
  assert(number > 0);
110
0
  return MakeFileName(name + "/" + kArchivalDirName, number, "log");
111
0
}
112
113
288k
std::string MakeTableFileName(const std::string& path, uint64_t number) {
114
288k
  return MakeFileName(path, number, kRocksDbTFileExt.c_str());
115
288k
}
116
117
7.63k
std::string MakeTableFileName(uint64_t number) {
118
7.63k
  return MakeFileName(number, kRocksDbTFileExt.c_str());
119
7.63k
}
120
121
0
std::string Rocks2LevelTableFileName(const std::string& fullname) {
122
0
  assert(fullname.size() > kRocksDbTFileExt.size() + 1);
123
0
  if (fullname.size() <= kRocksDbTFileExt.size() + 1) {
124
0
    return "";
125
0
  }
126
0
  return fullname.substr(0, fullname.size() - kRocksDbTFileExt.size()) +
127
0
         kLevelDbTFileExt;
128
0
}
129
130
0
uint64_t TableFileNameToNumber(const std::string& name) {
131
0
  uint64_t number = 0;
132
0
  uint64_t base = 1;
133
0
  int pos = static_cast<int>(name.find_last_of('.'));
134
0
  while (--pos >= 0 && name[pos] >= '0' && name[pos] <= '9') {
135
0
    number += (name[pos] - '0') * base;
136
0
    base *= 10;
137
0
  }
138
0
  return number;
139
0
}
140
141
std::string TableFileName(const std::vector<DbPath>& db_paths, uint64_t number,
142
163k
                          uint32_t path_id) {
143
163k
  assert(number > 0);
144
163k
  std::string path;
145
163k
  if (path_id >= db_paths.size()) {
146
0
    path = db_paths.back().path;
147
163k
  } else {
148
163k
    path = db_paths[path_id].path;
149
163k
  }
150
163k
  return MakeTableFileName(path, number);
151
163k
}
152
153
void FormatFileNumber(uint64_t number, uint32_t path_id, char* out_buf,
154
0
                      size_t out_buf_size) {
155
0
  if (path_id == 0) {
156
0
    snprintf(out_buf, out_buf_size, "%" PRIu64, number);
157
0
  } else {
158
0
    snprintf(out_buf, out_buf_size,
159
0
             "%" PRIu64
160
0
             "(path "
161
0
             "%" PRIu32 ")",
162
0
             number, path_id);
163
0
  }
164
0
}
165
166
214k
std::string DescriptorFileName(uint64_t number) {
167
214k
  assert(number > 0);
168
214k
  char buf[100];
169
214k
  snprintf(buf, sizeof(buf), "MANIFEST-%06llu",
170
214k
           static_cast<unsigned long long>(number));
171
214k
  return buf;
172
214k
}
173
174
214k
std::string DescriptorFileName(const std::string& dbname, uint64_t number) {
175
214k
  return dbname + "/" + DescriptorFileName(number);
176
214k
}
177
178
214k
std::string CurrentFileName(const std::string& dbname) {
179
214k
  return dbname + "/" + kCurrentFileName;
180
214k
}
181
182
57.3k
std::string LockFileName(const std::string& dbname) { return dbname + "/LOCK"; }
183
184
65.0k
std::string TempFileName(const std::string& dbname, uint64_t number) {
185
65.0k
  return MakeFileName(dbname, number, kTempFileNameSuffix.c_str());
186
65.0k
}
187
188
InfoLogPrefix::InfoLogPrefix(bool has_log_dir,
189
214k
                             const std::string& db_absolute_path) {
190
214k
  if (!has_log_dir) {
191
214k
    const char kInfoLogPrefix[] = "LOG";
192
    // "\0" is automatically added to the end
193
214k
    snprintf(buf, sizeof(buf), kInfoLogPrefix);
194
214k
    prefix = Slice(buf, sizeof(kInfoLogPrefix) - 1);
195
214k
  } else {
196
0
    size_t len =
197
0
        GetInfoLogPrefix(NormalizePath(db_absolute_path), buf, sizeof(buf));
198
0
    prefix = Slice(buf, len);
199
0
  }
200
214k
}
201
202
std::string InfoLogFileName(const std::string& dbname,
203
                            const std::string& db_path,
204
57.3k
                            const std::string& log_dir) {
205
57.3k
  if (log_dir.empty()) {
206
57.3k
    return dbname + "/LOG";
207
57.3k
  }
208
209
0
  InfoLogPrefix info_log_prefix(true, db_path);
210
0
  return log_dir + "/" + info_log_prefix.buf;
211
57.3k
}
212
213
// Return the name of the old info log file for "dbname".
214
std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts,
215
                               const std::string& db_path,
216
49.7k
                               const std::string& log_dir) {
217
49.7k
  char buf[50];
218
49.7k
  snprintf(buf, sizeof(buf), "%llu", static_cast<unsigned long long>(ts));
219
220
49.7k
  if (log_dir.empty()) {
221
49.7k
    return dbname + "/LOG.old." + buf;
222
49.7k
  }
223
224
0
  InfoLogPrefix info_log_prefix(true, db_path);
225
0
  return log_dir + "/" + info_log_prefix.buf + ".old." + buf;
226
49.7k
}
227
228
86.7k
std::string OptionsFileName(uint64_t file_num) {
229
86.7k
  char buffer[256];
230
86.7k
  snprintf(buffer, sizeof(buffer), "%s%06" PRIu64,
231
86.7k
           kOptionsFileNamePrefix.c_str(), file_num);
232
86.7k
  return buffer;
233
86.7k
}
234
86.7k
std::string OptionsFileName(const std::string& dbname, uint64_t file_num) {
235
86.7k
  return dbname + "/" + OptionsFileName(file_num);
236
86.7k
}
237
238
86.7k
std::string TempOptionsFileName(const std::string& dbname, uint64_t file_num) {
239
86.7k
  char buffer[256];
240
86.7k
  snprintf(buffer, sizeof(buffer), "%s%06" PRIu64 ".%s",
241
86.7k
           kOptionsFileNamePrefix.c_str(), file_num,
242
86.7k
           kTempFileNameSuffix.c_str());
243
86.7k
  return dbname + "/" + buffer;
244
86.7k
}
245
246
std::string CompactionProgressFileName(const std::string& dbname,
247
0
                                       uint64_t timestamp) {
248
0
  char buffer[256];
249
0
  snprintf(buffer, sizeof(buffer), "%s%llu",
250
0
           kCompactionProgressFileNamePrefix.c_str(),
251
0
           static_cast<unsigned long long>(timestamp));
252
0
  return dbname + "/" + buffer;
253
0
}
254
255
std::string TempCompactionProgressFileName(const std::string& dbname,
256
0
                                           uint64_t timestamp) {
257
0
  char buffer[256];
258
0
  snprintf(buffer, sizeof(buffer), "%s%llu.%s",
259
0
           kCompactionProgressFileNamePrefix.c_str(),
260
0
           static_cast<unsigned long long>(timestamp),
261
0
           kTempFileNameSuffix.c_str());
262
0
  return dbname + "/" + buffer;
263
0
}
264
265
0
std::string MetaDatabaseName(const std::string& dbname, uint64_t number) {
266
0
  char buf[100];
267
0
  snprintf(buf, sizeof(buf), "/METADB-%llu",
268
0
           static_cast<unsigned long long>(number));
269
0
  return dbname + buf;
270
0
}
271
272
91.8k
std::string IdentityFileName(const std::string& dbname) {
273
91.8k
  return dbname + "/IDENTITY";
274
91.8k
}
275
276
// Owned filenames have the form:
277
//    dbname/IDENTITY
278
//    dbname/CURRENT
279
//    dbname/LOCK
280
//    dbname/<info_log_name_prefix>
281
//    dbname/<info_log_name_prefix>.old.[0-9]+
282
//    dbname/MANIFEST-[0-9]+
283
//    dbname/[0-9]+.(log|sst|blob)
284
//    dbname/METADB-[0-9]+
285
//    dbname/OPTIONS-[0-9]+
286
//    dbname/OPTIONS-[0-9]+.dbtmp
287
//    dbname/COMPACTION_PROGRESS-[timestamp]
288
//    dbname/COMPACTION_PROGRESS-[timestamp].dbtmp
289
//    Disregards / at the beginning
290
bool ParseFileName(const std::string& fname, uint64_t* number, FileType* type,
291
4.94M
                   WalFileType* log_type) {
292
4.94M
  return ParseFileName(fname, number, "", type, log_type);
293
4.94M
}
294
295
bool ParseFileName(const std::string& fname, uint64_t* number,
296
                   const Slice& info_log_name_prefix, FileType* type,
297
11.3M
                   WalFileType* log_type) {
298
11.3M
  Slice rest(fname);
299
11.3M
  if (fname.length() > 1 && fname[0] == '/') {
300
4.15M
    rest.remove_prefix(1);
301
4.15M
  }
302
11.3M
  if (rest == "IDENTITY") {
303
534k
    *number = 0;
304
534k
    *type = kIdentityFile;
305
10.7M
  } else if (rest == "CURRENT") {
306
534k
    *number = 0;
307
534k
    *type = kCurrentFile;
308
10.2M
  } else if (rest == "LOCK") {
309
534k
    *number = 0;
310
534k
    *type = kDBLockFile;
311
9.72M
  } else if (info_log_name_prefix.size() > 0 &&
312
5.46M
             rest.starts_with(info_log_name_prefix)) {
313
3.32M
    rest.remove_prefix(info_log_name_prefix.size());
314
3.32M
    if (rest == "" || rest == ".old") {
315
306k
      *number = 0;
316
306k
      *type = kInfoLogFile;
317
3.02M
    } else if (rest.starts_with(".old.")) {
318
3.02M
      uint64_t ts_suffix;
319
      // sizeof also counts the trailing '\0'.
320
3.02M
      rest.remove_prefix(sizeof(".old.") - 1);
321
3.02M
      if (!ConsumeDecimalNumber(&rest, &ts_suffix)) {
322
0
        return false;
323
0
      }
324
3.02M
      *number = ts_suffix;
325
3.02M
      *type = kInfoLogFile;
326
3.02M
    }
327
6.39M
  } else if (rest.starts_with("MANIFEST-")) {
328
783k
    rest.remove_prefix(strlen("MANIFEST-"));
329
783k
    uint64_t num;
330
783k
    if (!ConsumeDecimalNumber(&rest, &num)) {
331
0
      return false;
332
0
    }
333
783k
    if (!rest.empty()) {
334
0
      return false;
335
0
    }
336
783k
    *type = kDescriptorFile;
337
783k
    *number = num;
338
5.61M
  } else if (rest.starts_with("METADB-")) {
339
0
    rest.remove_prefix(strlen("METADB-"));
340
0
    uint64_t num;
341
0
    if (!ConsumeDecimalNumber(&rest, &num)) {
342
0
      return false;
343
0
    }
344
0
    if (!rest.empty()) {
345
0
      return false;
346
0
    }
347
0
    *type = kMetaDatabase;
348
0
    *number = num;
349
5.61M
  } else if (rest.starts_with(kOptionsFileNamePrefix)) {
350
1.04M
    uint64_t ts_suffix;
351
1.04M
    bool is_temp_file = false;
352
1.04M
    rest.remove_prefix(kOptionsFileNamePrefix.size());
353
1.04M
    const std::string kTempFileNameSuffixWithDot =
354
1.04M
        std::string(".") + kTempFileNameSuffix;
355
1.04M
    if (rest.ends_with(kTempFileNameSuffixWithDot)) {
356
0
      rest.remove_suffix(kTempFileNameSuffixWithDot.size());
357
0
      is_temp_file = true;
358
0
    }
359
1.04M
    if (!ConsumeDecimalNumber(&rest, &ts_suffix)) {
360
0
      return false;
361
0
    }
362
1.04M
    *number = ts_suffix;
363
1.04M
    *type = is_temp_file ? kTempFile : kOptionsFile;
364
4.57M
  } else if (rest.starts_with(kCompactionProgressFileNamePrefix)) {
365
0
    uint64_t timestamp;
366
0
    bool is_temp_file = false;
367
0
    rest.remove_prefix(kCompactionProgressFileNamePrefix.size());
368
0
    const std::string kTempFileNameSuffixWithDot =
369
0
        std::string(".") + kTempFileNameSuffix;
370
0
    if (rest.ends_with(kTempFileNameSuffixWithDot)) {
371
0
      rest.remove_suffix(kTempFileNameSuffixWithDot.size());
372
0
      is_temp_file = true;
373
0
    }
374
0
    if (!ConsumeDecimalNumber(&rest, &timestamp)) {
375
0
      return false;
376
0
    }
377
0
    if (!rest.empty()) {
378
0
      return false;
379
0
    }
380
0
    *number = timestamp;
381
0
    *type = is_temp_file ? kTempFile : kCompactionProgressFile;
382
4.57M
  } else {
383
    // Avoid strtoull() to keep filename format independent of the
384
    // current locale
385
4.57M
    bool archive_dir_found = false;
386
4.57M
    if (rest.starts_with(kArchivalDirName)) {
387
0
      if (rest.size() <= kArchivalDirName.size()) {
388
0
        return false;
389
0
      }
390
0
      rest.remove_prefix(kArchivalDirName.size() +
391
0
                         1);  // Add 1 to remove / also
392
0
      if (log_type) {
393
0
        *log_type = kArchivedLogFile;
394
0
      }
395
0
      archive_dir_found = true;
396
0
    }
397
4.57M
    uint64_t num;
398
4.57M
    if (!ConsumeDecimalNumber(&rest, &num)) {
399
2.73M
      return false;
400
2.73M
    }
401
1.84M
    if (rest.size() <= 1 || rest[0] != '.') {
402
0
      return false;
403
0
    }
404
1.84M
    rest.remove_prefix(1);
405
406
1.84M
    Slice suffix = rest;
407
1.84M
    if (suffix == Slice("log")) {
408
691k
      *type = kWalFile;
409
691k
      if (log_type && !archive_dir_found) {
410
0
        *log_type = kAliveLogFile;
411
0
      }
412
1.15M
    } else if (archive_dir_found) {
413
0
      return false;  // Archive dir can contain only log files
414
1.15M
    } else if (suffix == Slice(kRocksDbTFileExt) ||
415
1.15M
               suffix == Slice(kLevelDbTFileExt)) {
416
1.15M
      *type = kTableFile;
417
1.15M
    } else if (suffix == Slice(kRocksDBBlobFileExt)) {
418
0
      *type = kBlobFile;
419
1
    } else if (suffix == Slice(kTempFileNameSuffix)) {
420
0
      *type = kTempFile;
421
1
    } else {
422
1
      return false;
423
1
    }
424
1.84M
    *number = num;
425
1.84M
  }
426
8.60M
  return true;
427
11.3M
}
428
429
IOStatus SetCurrentFile(const WriteOptions& write_options, FileSystem* fs,
430
                        const std::string& dbname, uint64_t descriptor_number,
431
                        Temperature temp,
432
57.3k
                        FSDirectory* dir_contains_current_file) {
433
  // Remove leading "dbname/" and add newline to manifest file name
434
57.3k
  std::string manifest = DescriptorFileName(dbname, descriptor_number);
435
57.3k
  Slice contents = manifest;
436
57.3k
  assert(contents.starts_with(dbname + "/"));
437
57.3k
  contents.remove_prefix(dbname.size() + 1);
438
57.3k
  std::string tmp = TempFileName(dbname, descriptor_number);
439
57.3k
  IOOptions opts;
440
57.3k
  IOStatus s = PrepareIOFromWriteOptions(write_options, opts);
441
57.3k
  FileOptions file_opts;
442
57.3k
  file_opts.temperature = temp;
443
57.3k
  if (s.ok()) {
444
57.3k
    s = WriteStringToFile(fs, contents.ToString() + "\n", tmp, true, opts,
445
57.3k
                          file_opts);
446
57.3k
  }
447
57.3k
  TEST_SYNC_POINT_CALLBACK("SetCurrentFile:BeforeRename", &s);
448
57.3k
  if (s.ok()) {
449
57.3k
    TEST_KILL_RANDOM_WITH_WEIGHT("SetCurrentFile:0", REDUCE_ODDS2);
450
57.3k
    s = fs->RenameFile(tmp, CurrentFileName(dbname), opts, nullptr);
451
57.3k
    TEST_KILL_RANDOM_WITH_WEIGHT("SetCurrentFile:1", REDUCE_ODDS2);
452
57.3k
    TEST_SYNC_POINT_CALLBACK("SetCurrentFile:AfterRename", &s);
453
57.3k
  }
454
57.3k
  if (s.ok()) {
455
57.3k
    if (dir_contains_current_file != nullptr) {
456
57.3k
      s = dir_contains_current_file->FsyncWithDirOptions(
457
57.3k
          opts, nullptr, DirFsyncOptions(CurrentFileName(dbname)));
458
57.3k
    }
459
57.3k
  } else {
460
0
    fs->DeleteFile(tmp, opts, nullptr)
461
0
        .PermitUncheckedError();  // NOTE: PermitUncheckedError is acceptable
462
                                  // here as we are already handling an error
463
                                  // case, and this is just a best-attempt
464
                                  // effort at some cleanup
465
0
  }
466
57.3k
  return s;
467
57.3k
}
468
469
Status SetIdentityFile(const WriteOptions& write_options, Env* env,
470
                       const std::string& dbname, Temperature temp,
471
7.64k
                       const std::string& db_id) {
472
7.64k
  std::string id;
473
7.64k
  if (db_id.empty()) {
474
0
    id = env->GenerateUniqueId();
475
7.64k
  } else {
476
7.64k
    id = db_id;
477
7.64k
  }
478
7.64k
  assert(!id.empty());
479
  // Reserve the filename dbname/000000.dbtmp for the temporary identity file
480
7.64k
  std::string tmp = TempFileName(dbname, 0);
481
7.64k
  std::string identify_file_name = IdentityFileName(dbname);
482
7.64k
  Status s;
483
7.64k
  IOOptions opts;
484
7.64k
  s = PrepareIOFromWriteOptions(write_options, opts);
485
7.64k
  FileOptions file_opts;
486
7.64k
  file_opts.temperature = temp;
487
7.64k
  if (s.ok()) {
488
7.64k
    s = WriteStringToFile(env->GetFileSystem().get(), id, tmp,
489
7.64k
                          /*should_sync=*/true, opts, file_opts);
490
7.64k
  }
491
7.64k
  if (s.ok()) {
492
7.64k
    s = env->RenameFile(tmp, identify_file_name);
493
7.64k
  }
494
7.64k
  std::unique_ptr<FSDirectory> dir_obj;
495
7.64k
  if (s.ok()) {
496
7.64k
    s = env->GetFileSystem()->NewDirectory(dbname, opts, &dir_obj, nullptr);
497
7.64k
  }
498
7.64k
  if (s.ok()) {
499
7.64k
    s = dir_obj->FsyncWithDirOptions(opts, nullptr,
500
7.64k
                                     DirFsyncOptions(identify_file_name));
501
7.64k
  }
502
503
  // The default Close() could return "NotSupported" and we bypass it
504
  // if it is not impelmented. Detailed explanations can be found in
505
  // db/db_impl/db_impl.h
506
7.64k
  if (s.ok()) {
507
7.64k
    Status temp_s = dir_obj->Close(opts, nullptr);
508
7.64k
    if (!temp_s.ok()) {
509
0
      if (temp_s.IsNotSupported()) {
510
0
        temp_s.PermitUncheckedError();
511
0
      } else {
512
0
        s = temp_s;
513
0
      }
514
0
    }
515
7.64k
  }
516
7.64k
  if (!s.ok()) {
517
0
    env->DeleteFile(tmp).PermitUncheckedError();
518
0
  }
519
7.64k
  return s;
520
7.64k
}
521
522
IOStatus SyncManifest(const ImmutableDBOptions* db_options,
523
                      const WriteOptions& write_options,
524
102k
                      WritableFileWriter* file) {
525
102k
  TEST_KILL_RANDOM_WITH_WEIGHT("SyncManifest:0", REDUCE_ODDS2);
526
102k
  StopWatch sw(db_options->clock, db_options->stats, MANIFEST_FILE_SYNC_MICROS);
527
102k
  IOOptions io_options;
528
102k
  IOStatus s = PrepareIOFromWriteOptions(write_options, io_options);
529
102k
  if (!s.ok()) {
530
0
    return s;
531
0
  }
532
102k
  return file->Sync(io_options, db_options->use_fsync);
533
102k
}
534
535
Status GetInfoLogFiles(const std::shared_ptr<FileSystem>& fs,
536
                       const std::string& db_log_dir, const std::string& dbname,
537
                       std::string* parent_dir,
538
0
                       std::vector<std::string>* info_log_list) {
539
0
  assert(parent_dir != nullptr);
540
0
  assert(info_log_list != nullptr);
541
0
  uint64_t number = 0;
542
0
  FileType type = kWalFile;
543
544
0
  if (!db_log_dir.empty()) {
545
0
    *parent_dir = db_log_dir;
546
0
  } else {
547
0
    *parent_dir = dbname;
548
0
  }
549
550
0
  InfoLogPrefix info_log_prefix(!db_log_dir.empty(), dbname);
551
552
0
  std::vector<std::string> file_names;
553
0
  Status s = fs->GetChildren(*parent_dir, IOOptions(), &file_names, nullptr);
554
555
0
  if (!s.ok()) {
556
0
    return s;
557
0
  }
558
559
0
  for (auto& f : file_names) {
560
0
    if (ParseFileName(f, &number, info_log_prefix.prefix, &type) &&
561
0
        (type == kInfoLogFile)) {
562
0
      info_log_list->push_back(f);
563
0
    }
564
0
  }
565
0
  return Status::OK();
566
0
}
567
568
670k
std::string NormalizePath(const std::string& path) {
569
670k
  std::string dst;
570
571
670k
  if (path.length() > 2 && path[0] == kFilePathSeparator &&
572
670k
      path[1] == kFilePathSeparator) {  // Handle UNC names
573
0
    dst.append(2, kFilePathSeparator);
574
0
  }
575
576
8.49M
  for (auto c : path) {
577
8.49M
    if (!dst.empty() && (c == kFilePathSeparator || c == '/') &&
578
670k
        (dst.back() == kFilePathSeparator || dst.back() == '/')) {
579
0
      continue;
580
0
    }
581
8.49M
    dst.push_back(c);
582
8.49M
  }
583
670k
  return dst;
584
670k
}
585
586
}  // namespace ROCKSDB_NAMESPACE