YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/memenv/memenv.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file. See the AUTHORS file for names of contributors.
4
//
5
// The following only applies to changes made to this file as part of YugaByte development.
6
//
7
// Portions Copyright (c) YugaByte, Inc.
8
//
9
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
10
// in compliance with the License.  You may obtain a copy of the License at
11
//
12
// http://www.apache.org/licenses/LICENSE-2.0
13
//
14
// Unless required by applicable law or agreed to in writing, software distributed under the License
15
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
16
// or implied.  See the License for the specific language governing permissions and limitations
17
// under the License.
18
//
19
// Modified for yb:
20
// - use boost mutexes instead of port mutexes
21
#include "yb/util/memenv/memenv.h"
22
23
#include <string.h>
24
25
#include <map>
26
#include <random>
27
#include <string>
28
#include <vector>
29
30
#include <glog/logging.h>
31
32
#include "yb/gutil/map-util.h"
33
#include "yb/gutil/stringprintf.h"
34
#include "yb/gutil/strings/strip.h"
35
#include "yb/gutil/walltime.h"
36
#include "yb/util/env.h"
37
#include "yb/util/file_system_mem.h"
38
#include "yb/util/malloc.h"
39
#include "yb/util/mutex.h"
40
#include "yb/util/random.h"
41
#include "yb/util/result.h"
42
#include "yb/util/status.h"
43
44
namespace yb {
45
46
namespace {
47
48
using std::string;
49
using std::vector;
50
using strings::Substitute;
51
52
class RandomAccessFileImpl : public RandomAccessFile {
53
 public:
54
  explicit RandomAccessFileImpl(const std::shared_ptr<InMemoryFileState>& file)
55
3
    : file_(std::move(file)) {
56
3
  }
57
58
3
  ~RandomAccessFileImpl() {
59
3
  }
60
61
12
  virtual Status Read(uint64_t offset, size_t n, Slice* result, uint8_t* scratch) const override {
62
12
    return file_->Read(offset, n, result, scratch);
63
12
  }
64
65
1
  Result<uint64_t> Size() const override {
66
1
    return file_->Size();
67
1
  }
68
69
0
  Result<uint64_t> INode() const override {
70
0
    return 0;
71
0
  }
72
73
0
  const string& filename() const override {
74
0
    return file_->filename();
75
0
  }
76
77
0
  size_t memory_footprint() const override {
78
    // The InMemoryFileState is actually shared between multiple files, but the double
79
    // counting doesn't matter much since MemEnv is only used in tests.
80
0
    return malloc_usable_size(this) + file_->memory_footprint();
81
0
  }
82
83
 private:
84
  const std::shared_ptr<InMemoryFileState> file_;
85
};
86
87
class WritableFileImpl : public WritableFile {
88
 public:
89
  explicit WritableFileImpl(const std::shared_ptr<InMemoryFileState>& file)
90
23
    : file_(file) {
91
23
  }
92
93
23
  ~WritableFileImpl() {
94
23
  }
95
96
0
  Status PreAllocate(uint64_t size) override {
97
0
    return file_->PreAllocate(size);
98
0
  }
99
100
21
  Status Append(const Slice& data) override {
101
21
    return file_->Append(data);
102
21
  }
103
104
  // This is a dummy implementation that simply serially appends all
105
  // slices using regular I/O.
106
0
  Status AppendSlices(const Slice* slices, size_t num) override {
107
0
    for (const auto* end = slices + num; slices != end; ++slices) {
108
0
      RETURN_NOT_OK(file_->Append(*slices));
109
0
    }
110
0
    return Status::OK();
111
0
  }
112
113
14
  Status Close() override { return Status::OK(); }
114
115
2
  Status Flush(FlushMode mode) override { return Status::OK(); }
116
117
1
  Status Sync() override { return Status::OK(); }
118
119
4
  uint64_t Size() const override { return file_->Size(); }
120
121
0
  const string& filename() const override {
122
0
    return file_->filename();
123
0
  }
124
125
 private:
126
  const std::shared_ptr<InMemoryFileState> file_;
127
};
128
129
class RWFileImpl : public RWFile {
130
 public:
131
  explicit RWFileImpl(const std::shared_ptr<InMemoryFileState>& file)
132
2
    : file_(file) {
133
2
  }
134
135
2
  ~RWFileImpl() {
136
2
  }
137
138
  virtual Status Read(uint64_t offset, size_t length,
139
2
                      Slice* result, uint8_t* scratch) const override {
140
2
    return file_->Read(offset, length, result, scratch);
141
2
  }
142
143
2
  Status Write(uint64_t offset, const Slice& data) override {
144
2
    uint64_t file_size = file_->Size();
145
    // TODO: Modify InMemoryFileState to allow rewriting.
146
2
    if (offset < file_size) {
147
1
      return STATUS(NotSupported, "In-memory RW file does not support random writing");
148
1
    } else if (offset > file_size) {
149
      // Fill in the space between with zeroes.
150
0
      std::string zeroes(offset - file_size, '\0');
151
0
      RETURN_NOT_OK(file_->Append(zeroes));
152
0
    }
153
1
    return file_->Append(data);
154
2
  }
155
156
0
  Status PreAllocate(uint64_t offset, size_t length) override {
157
0
    return Status::OK();
158
0
  }
159
160
0
  Status PunchHole(uint64_t offset, size_t length) override {
161
0
    return Status::OK();
162
0
  }
163
164
0
  Status Flush(FlushMode mode, uint64_t offset, size_t length) override {
165
0
    return Status::OK();
166
0
  }
167
168
0
  Status Sync() override {
169
0
    return Status::OK();
170
0
  }
171
172
0
  Status Close() override {
173
0
    return Status::OK();
174
0
  }
175
176
0
  Status Size(uint64_t* size) const override {
177
0
    *size = file_->Size();
178
0
    return Status::OK();
179
0
  }
180
181
0
  const string& filename() const override {
182
0
    return file_->filename();
183
0
  }
184
185
 private:
186
  const std::shared_ptr<InMemoryFileState> file_;
187
};
188
189
class InMemoryEnv : public EnvWrapper {
190
 public:
191
11
  explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { }
192
193
11
  virtual ~InMemoryEnv() {
194
11
  }
195
196
  // Partial implementation of the Env interface.
197
  virtual Status NewSequentialFile(const std::string& fname,
198
3
                                   std::unique_ptr<SequentialFile>* result) override {
199
3
    MutexLock lock(mutex_);
200
3
    if (file_map_.find(fname) == file_map_.end()) {
201
1
      return STATUS(IOError, fname, "File not found");
202
1
    }
203
204
2
    result->reset(new InMemorySequentialFile(file_map_[fname]));
205
2
    return Status::OK();
206
3
  }
207
208
  virtual Status NewRandomAccessFile(const std::string& fname,
209
4
                                     std::unique_ptr<RandomAccessFile>* result) override {
210
4
    MutexLock lock(mutex_);
211
4
    if (file_map_.find(fname) == file_map_.end()) {
212
1
      return STATUS(IOError, fname, "File not found");
213
1
    }
214
215
3
    result->reset(new RandomAccessFileImpl(file_map_[fname]));
216
3
    return Status::OK();
217
4
  }
218
219
  virtual Status NewWritableFile(const WritableFileOptions& opts,
220
                                 const std::string& fname,
221
14
                                 std::unique_ptr<WritableFile>* result) override {
222
14
    std::unique_ptr<WritableFileImpl> wf;
223
14
    RETURN_NOT_OK(CreateAndRegisterNewFile(fname, opts.mode, &wf));
224
13
    result->reset(wf.release());
225
13
    return Status::OK();
226
14
  }
227
228
  virtual Status NewWritableFile(const std::string& fname,
229
7
                                 std::unique_ptr<WritableFile>* result) override {
230
7
    return NewWritableFile(WritableFileOptions(), fname, result);
231
7
  }
232
233
  virtual Status NewRWFile(const RWFileOptions& opts,
234
                           const string& fname,
235
3
                           std::unique_ptr<RWFile>* result) override {
236
3
    std::unique_ptr<RWFileImpl> rwf;
237
3
    RETURN_NOT_OK(CreateAndRegisterNewFile(fname, opts.mode, &rwf));
238
2
    result->reset(rwf.release());
239
2
    return Status::OK();
240
3
  }
241
242
  virtual Status NewRWFile(const string& fname,
243
1
                           std::unique_ptr<RWFile>* result) override {
244
1
    return NewRWFile(RWFileOptions(), fname, result);
245
1
  }
246
247
  virtual Status NewTempWritableFile(const WritableFileOptions& opts,
248
                                     const std::string& name_template,
249
                                     std::string* created_filename,
250
11
                                     std::unique_ptr<WritableFile>* result) override {
251
    // Not very random, but InMemoryEnv is basically a test env.
252
11
    std::mt19937_64 random(GetCurrentTimeMicros());
253
11
    while (true) {
254
11
      string stripped;
255
11
      if (!TryStripSuffixString(name_template, "XXXXXX", &stripped)) {
256
1
        return STATUS(InvalidArgument, "Name template must end with the string XXXXXX",
257
1
                                       name_template);
258
1
      }
259
10
      uint32_t num = random() % 999999; // Ensure it's <= 6 digits long.
260
10
      string path = StringPrintf("%s%06u", stripped.c_str(), num);
261
262
10
      MutexLock lock(mutex_);
263
10
      if (!ContainsKey(file_map_, path)) {
264
10
        CreateAndRegisterNewWritableFileUnlocked<WritableFile, WritableFileImpl>(path, result);
265
10
        *created_filename = path;
266
10
        return Status::OK();
267
10
      }
268
10
    }
269
    // Unreachable.
270
11
  }
271
272
8
  bool FileExists(const std::string& fname) override {
273
8
    MutexLock lock(mutex_);
274
8
    return file_map_.find(fname) != file_map_.end();
275
8
  }
276
277
  CHECKED_STATUS GetChildren(const std::string& dir,
278
                             ExcludeDots exclude_dots,
279
3
                             vector<std::string>* result) override {
280
3
    MutexLock lock(mutex_);
281
3
    result->clear();
282
283
4
    for (const auto& file : file_map_) {
284
4
      const std::string& filename = file.first;
285
286
4
      if (filename.size() >= dir.size() + 1 && 
filename[dir.size()] == '/'1
&&
287
4
          
Slice(filename).starts_with(Slice(dir))1
) {
288
1
        result->push_back(filename.substr(dir.size() + 1));
289
1
      }
290
4
    }
291
292
3
    return Status::OK();
293
3
  }
294
295
13
  Status DeleteFile(const std::string& fname) override {
296
13
    MutexLock lock(mutex_);
297
13
    if (file_map_.find(fname) == file_map_.end()) {
298
1
      return STATUS(IOError, fname, "File not found");
299
1
    }
300
301
12
    DeleteFileInternal(fname);
302
12
    return Status::OK();
303
13
  }
304
305
2
  Status CreateDir(const std::string& dirname) override {
306
2
    std::unique_ptr<WritableFile> file;
307
2
    return NewWritableFile(dirname, &file);
308
2
  }
309
310
1
  Status DeleteDir(const std::string& dirname) override {
311
1
    return DeleteFile(dirname);
312
1
  }
313
314
0
  Status SyncDir(const std::string& dirname) override {
315
0
    return Status::OK();
316
0
  }
317
318
0
  Status DeleteRecursively(const std::string& dirname) override {
319
0
    CHECK(!dirname.empty());
320
0
    string dir(dirname);
321
0
    if (dir[dir.size() - 1] != '/') {
322
0
      dir.push_back('/');
323
0
    }
324
325
0
    MutexLock lock(mutex_);
326
327
0
    for (auto i = file_map_.begin(); i != file_map_.end();) {
328
0
      const std::string& filename = i->first;
329
330
0
      if (filename.size() >= dir.size() && Slice(filename).starts_with(Slice(dir))) {
331
0
        file_map_.erase(i++);
332
0
      } else {
333
0
        ++i;
334
0
      }
335
0
    }
336
337
0
    return Status::OK();
338
0
  }
339
340
4
  Result<uint64_t> GetFileSize(const std::string& fname) override {
341
4
    MutexLock lock(mutex_);
342
4
    if (file_map_.find(fname) == file_map_.end()) {
343
1
      return STATUS(IOError, fname, "File not found");
344
1
    }
345
346
3
    return file_map_[fname]->Size();
347
4
  }
348
349
0
  Result<uint64_t> GetFileINode(const std::string& fname) override {
350
0
    return 0;
351
0
  }
352
353
0
  Result<uint64_t> GetFileSizeOnDisk(const std::string& fname) override {
354
0
    return GetFileSize(fname);
355
0
  }
356
357
0
  Result<uint64_t> GetBlockSize(const string& fname) override {
358
    // The default for ext3/ext4 filesystems.
359
0
    return 4096;
360
0
  }
361
362
  virtual Status RenameFile(const std::string& src,
363
2
                            const std::string& target) override {
364
2
    MutexLock lock(mutex_);
365
2
    if (file_map_.find(src) == file_map_.end()) {
366
1
      return STATUS(IOError, src, "File not found");
367
1
    }
368
369
1
    DeleteFileInternal(target);
370
1
    file_map_[target] = file_map_[src];
371
1
    file_map_.erase(src);
372
1
    return Status::OK();
373
2
  }
374
375
  virtual Status LockFile(const std::string& fname,
376
                          FileLock** lock,
377
1
                          bool recursive_lock_ok) override {
378
1
    *lock = new FileLock;
379
1
    return Status::OK();
380
1
  }
381
382
1
  Status UnlockFile(FileLock* lock) override {
383
1
    delete lock;
384
1
    return Status::OK();
385
1
  }
386
387
1
  Status GetTestDirectory(std::string* path) override {
388
1
    *path = "/test";
389
1
    return Status::OK();
390
1
  }
391
392
  virtual Status Walk(const std::string& root,
393
                      DirectoryOrder order,
394
0
                      const WalkCallback& cb) override {
395
0
    LOG(FATAL) << "Not implemented";
396
0
  }
397
398
0
  Status Canonicalize(const string& path, string* result) override {
399
0
    *result = path;
400
0
    return Status::OK();
401
0
  }
402
403
0
  Status GetTotalRAMBytes(int64_t* ram) override {
404
0
    LOG(FATAL) << "Not implemented";
405
0
  }
406
407
0
  Result<uint64_t> GetFreeSpaceBytes(const std::string& path) override {
408
0
    LOG(FATAL) << "Not implemented";
409
0
  }
410
411
0
  bool IsEncrypted() const override {
412
0
    return false;
413
0
  }
414
415
 private:
416
15
  void DeleteFileInternal(const std::string& fname) {
417
15
    if (!ContainsKey(file_map_, fname)) {
418
1
      return;
419
1
    }
420
14
    file_map_.erase(fname);
421
14
  }
422
423
  // Create new internal representation of a writable file.
424
  template <typename PtrType, typename ImplType>
425
  void CreateAndRegisterNewWritableFileUnlocked(const string& path,
426
23
                                                std::unique_ptr<PtrType>* result) {
427
23
    file_map_[path] = std::make_shared<InMemoryFileState>(path);
428
23
    result->reset(new ImplType(file_map_[path]));
429
23
  }
memenv.cc:void yb::(anonymous namespace)::InMemoryEnv::CreateAndRegisterNewWritableFileUnlocked<yb::(anonymous namespace)::WritableFileImpl, yb::(anonymous namespace)::WritableFileImpl>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::unique_ptr<yb::(anonymous namespace)::WritableFileImpl, std::__1::default_delete<yb::(anonymous namespace)::WritableFileImpl> >*)
Line
Count
Source
426
12
                                                std::unique_ptr<PtrType>* result) {
427
12
    file_map_[path] = std::make_shared<InMemoryFileState>(path);
428
12
    result->reset(new ImplType(file_map_[path]));
429
12
  }
memenv.cc:void yb::(anonymous namespace)::InMemoryEnv::CreateAndRegisterNewWritableFileUnlocked<yb::WritableFile, yb::(anonymous namespace)::WritableFileImpl>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::unique_ptr<yb::WritableFile, std::__1::default_delete<yb::WritableFile> >*)
Line
Count
Source
426
10
                                                std::unique_ptr<PtrType>* result) {
427
10
    file_map_[path] = std::make_shared<InMemoryFileState>(path);
428
10
    result->reset(new ImplType(file_map_[path]));
429
10
  }
memenv.cc:void yb::(anonymous namespace)::InMemoryEnv::CreateAndRegisterNewWritableFileUnlocked<yb::(anonymous namespace)::RWFileImpl, yb::(anonymous namespace)::RWFileImpl>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::unique_ptr<yb::(anonymous namespace)::RWFileImpl, std::__1::default_delete<yb::(anonymous namespace)::RWFileImpl> >*)
Line
Count
Source
426
1
                                                std::unique_ptr<PtrType>* result) {
427
1
    file_map_[path] = std::make_shared<InMemoryFileState>(path);
428
1
    result->reset(new ImplType(file_map_[path]));
429
1
  }
430
431
  // Create new internal representation of a file.
432
  template <typename Type>
433
  Status CreateAndRegisterNewFile(const string& fname,
434
                                  CreateMode mode,
435
17
                                  std::unique_ptr<Type>* result) {
436
17
    MutexLock lock(mutex_);
437
17
    if (ContainsKey(file_map_, fname)) {
438
6
      switch (mode) {
439
2
        case CREATE_IF_NON_EXISTING_TRUNCATE:
440
2
          DeleteFileInternal(fname);
441
2
          break; // creates a new file below
442
2
        case CREATE_NON_EXISTING:
443
2
          return STATUS(AlreadyPresent, fname, "File already exists");
444
2
        case OPEN_EXISTING:
445
2
          result->reset(new Type(file_map_[fname]));
446
2
          return Status::OK();
447
0
        default:
448
0
          return STATUS(NotSupported, Substitute("Unknown create mode $0",
449
6
                                                 mode));
450
6
      }
451
11
    } else if (mode == OPEN_EXISTING) {
452
0
      return STATUS(IOError, fname, "File not found");
453
0
    }
454
455
13
    CreateAndRegisterNewWritableFileUnlocked<Type, Type>(fname, result);
456
13
    return Status::OK();
457
17
  }
memenv.cc:yb::Status yb::(anonymous namespace)::InMemoryEnv::CreateAndRegisterNewFile<yb::(anonymous namespace)::WritableFileImpl>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, yb::Env::CreateMode, std::__1::unique_ptr<yb::(anonymous namespace)::WritableFileImpl, std::__1::default_delete<yb::(anonymous namespace)::WritableFileImpl> >*)
Line
Count
Source
435
14
                                  std::unique_ptr<Type>* result) {
436
14
    MutexLock lock(mutex_);
437
14
    if (ContainsKey(file_map_, fname)) {
438
4
      switch (mode) {
439
2
        case CREATE_IF_NON_EXISTING_TRUNCATE:
440
2
          DeleteFileInternal(fname);
441
2
          break; // creates a new file below
442
1
        case CREATE_NON_EXISTING:
443
1
          return STATUS(AlreadyPresent, fname, "File already exists");
444
1
        case OPEN_EXISTING:
445
1
          result->reset(new Type(file_map_[fname]));
446
1
          return Status::OK();
447
0
        default:
448
0
          return STATUS(NotSupported, Substitute("Unknown create mode $0",
449
4
                                                 mode));
450
4
      }
451
10
    } else if (mode == OPEN_EXISTING) {
452
0
      return STATUS(IOError, fname, "File not found");
453
0
    }
454
455
12
    CreateAndRegisterNewWritableFileUnlocked<Type, Type>(fname, result);
456
12
    return Status::OK();
457
14
  }
memenv.cc:yb::Status yb::(anonymous namespace)::InMemoryEnv::CreateAndRegisterNewFile<yb::(anonymous namespace)::RWFileImpl>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, yb::Env::CreateMode, std::__1::unique_ptr<yb::(anonymous namespace)::RWFileImpl, std::__1::default_delete<yb::(anonymous namespace)::RWFileImpl> >*)
Line
Count
Source
435
3
                                  std::unique_ptr<Type>* result) {
436
3
    MutexLock lock(mutex_);
437
3
    if (ContainsKey(file_map_, fname)) {
438
2
      switch (mode) {
439
0
        case CREATE_IF_NON_EXISTING_TRUNCATE:
440
0
          DeleteFileInternal(fname);
441
0
          break; // creates a new file below
442
1
        case CREATE_NON_EXISTING:
443
1
          return STATUS(AlreadyPresent, fname, "File already exists");
444
1
        case OPEN_EXISTING:
445
1
          result->reset(new Type(file_map_[fname]));
446
1
          return Status::OK();
447
0
        default:
448
0
          return STATUS(NotSupported, Substitute("Unknown create mode $0",
449
2
                                                 mode));
450
2
      }
451
2
    } else 
if (1
mode == OPEN_EXISTING1
) {
452
0
      return STATUS(IOError, fname, "File not found");
453
0
    }
454
455
1
    CreateAndRegisterNewWritableFileUnlocked<Type, Type>(fname, result);
456
1
    return Status::OK();
457
3
  }
458
459
  // Map from filenames to InMemoryFileState objects, representing a simple file system.
460
  typedef std::map<std::string, std::shared_ptr<InMemoryFileState>> FileSystem;
461
  Mutex mutex_;
462
  FileSystem file_map_;  // Protected by mutex_.
463
};
464
465
}  // namespace
466
467
11
Env* NewMemEnv(Env* base_env) {
468
11
  return new InMemoryEnv(base_env);
469
11
}
470
471
} // namespace yb