/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 |