Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: third_party/leveldatabase/env_chromium.cc

Issue 7522008: Move chromium-specific files from leveldb to chromium. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix win compile error, roll leveldb Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include <deque>
6 #include <errno.h>
7 #include <stdio.h>
8 #include "base/at_exit.h"
9 #include "base/file_path.h"
10 #include "base/file_util.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/message_loop.h"
14 #include "base/platform_file.h"
15 #include "base/process_util.h"
16 #include "base/synchronization/lock.h"
17 #include "base/sys_info.h"
18 #include "base/task.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread.h"
21 #include "base/utf_string_conversions.h"
22 #include "leveldb/env.h"
23 #include "leveldb/slice.h"
24 #include "port/port.h"
25 #include "util/logging.h"
26 #include "util/posix_logger.h"
27
28 #if defined(OS_WIN)
29 #include <io.h>
30 #include "base/win/win_util.h"
31 #endif
32
33 #if defined(OS_MACOSX) || defined(OS_WIN)
34 // The following are glibc-specific
35 namespace {
36
37 size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *file) {
38 return fread(ptr, size, n, file);
39 }
40
41 size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *file) {
42 return fwrite(ptr, size, n, file);
43 }
44
45 int fflush_unlocked(FILE *file) {
46 return fflush(file);
47 }
48
49 int fdatasync(int fildes) {
50 #if defined(OS_WIN)
51 return _commit(fildes);
52 #else
53 return fsync(fildes);
54 #endif
55 }
56
57 }
58 #endif
59
60 namespace leveldb {
61
62 namespace {
63
64 class Thread;
65
66 static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[]
67 = FILE_PATH_LITERAL("leveldb-test-");
68
69 ::FilePath CreateFilePath(const std::string& file_path) {
70 #if defined(OS_WIN)
71 return FilePath(UTF8ToUTF16(file_path));
72 #else
73 return FilePath(file_path);
74 #endif
75 }
76
77 std::string FilePathToString(const ::FilePath& file_path) {
78 #if defined(OS_WIN)
79 return UTF16ToUTF8(file_path.value());
80 #else
81 return file_path.value();
82 #endif
83 }
84
85 // TODO(jorlow): This should be moved into Chromium's base.
86 const char* PlatformFileErrorString(const ::base::PlatformFileError& error) {
87 switch (error) {
88 case ::base::PLATFORM_FILE_ERROR_FAILED:
89 return "Opening file failed.";
90 case ::base::PLATFORM_FILE_ERROR_IN_USE:
91 return "File currently in use.";
92 case ::base::PLATFORM_FILE_ERROR_EXISTS:
93 return "File already exists.";
94 case ::base::PLATFORM_FILE_ERROR_NOT_FOUND:
95 return "File not found.";
96 case ::base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
97 return "Access denied.";
98 case ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
99 return "Too many files open.";
100 case ::base::PLATFORM_FILE_ERROR_NO_MEMORY:
101 return "Out of memory.";
102 case ::base::PLATFORM_FILE_ERROR_NO_SPACE:
103 return "No space left on drive.";
104 case ::base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
105 return "Not a directory.";
106 case ::base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
107 return "Invalid operation.";
108 case ::base::PLATFORM_FILE_ERROR_SECURITY:
109 return "Security error.";
110 case ::base::PLATFORM_FILE_ERROR_ABORT:
111 return "File operation aborted.";
112 case ::base::PLATFORM_FILE_ERROR_NOT_A_FILE:
113 return "The supplied path was not a file.";
114 case ::base::PLATFORM_FILE_ERROR_NOT_EMPTY:
115 return "The file was not empty.";
116 }
117 NOTIMPLEMENTED();
118 return "Unknown error.";
119 }
120
121 class ChromiumSequentialFile: public SequentialFile {
122 private:
123 std::string filename_;
124 FILE* file_;
125
126 public:
127 ChromiumSequentialFile(const std::string& fname, FILE* f)
128 : filename_(fname), file_(f) { }
129 virtual ~ChromiumSequentialFile() { fclose(file_); }
130
131 virtual Status Read(size_t n, Slice* result, char* scratch) {
132 Status s;
133 size_t r = fread_unlocked(scratch, 1, n, file_);
134 *result = Slice(scratch, r);
135 if (r < n) {
136 if (feof(file_)) {
137 // We leave status as ok if we hit the end of the file
138 } else {
139 // A partial read with an error: return a non-ok status
140 s = Status::IOError(filename_, strerror(errno));
141 }
142 }
143 return s;
144 }
145
146 virtual Status Skip(uint64_t n) {
147 if (fseek(file_, n, SEEK_CUR)) {
148 return Status::IOError(filename_, strerror(errno));
149 }
150 return Status::OK();
151 }
152 };
153
154 class ChromiumRandomAccessFile: public RandomAccessFile {
155 private:
156 std::string filename_;
157 ::base::PlatformFile file_;
158
159 public:
160 ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file)
161 : filename_(fname), file_(file) { }
162 virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
163
164 virtual Status Read(uint64_t offset, size_t n, Slice* result,
165 char* scratch) const {
166 Status s;
167 int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
168 *result = Slice(scratch, (r < 0) ? 0 : r);
169 if (r < 0) {
170 // An error: return a non-ok status
171 s = Status::IOError(filename_, "Could not preform read");
172 }
173 return s;
174 }
175 };
176
177 class ChromiumWritableFile : public WritableFile {
178 private:
179 std::string filename_;
180 FILE* file_;
181
182 public:
183 ChromiumWritableFile(const std::string& fname, FILE* f)
184 : filename_(fname), file_(f) { }
185
186 ~ChromiumWritableFile() {
187 if (file_ != NULL) {
188 // Ignoring any potential errors
189 fclose(file_);
190 }
191 }
192
193 virtual Status Append(const Slice& data) {
194 size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
195 Status result;
196 if (r != data.size()) {
197 result = Status::IOError(filename_, strerror(errno));
198 }
199 return result;
200 }
201
202 virtual Status Close() {
203 Status result;
204 if (fclose(file_) != 0) {
205 result = Status::IOError(filename_, strerror(errno));
206 }
207 file_ = NULL;
208 return result;
209 }
210
211 virtual Status Flush() {
212 Status result;
213 if (fflush_unlocked(file_) != 0) {
214 result = Status::IOError(filename_, strerror(errno));
215 }
216 return result;
217 }
218
219 virtual Status Sync() {
220 Status result;
221 if ((fflush_unlocked(file_) != 0) ||
222 (fdatasync(fileno(file_)) != 0)) {
223 result = Status::IOError(filename_, strerror(errno));
224 }
225 return result;
226 }
227 };
228
229 class ChromiumFileLock : public FileLock {
230 public:
231 ::base::PlatformFile file_;
232 };
233
234 class ChromiumEnv : public Env {
235 public:
236 ChromiumEnv();
237 virtual ~ChromiumEnv() {
238 fprintf(stderr, "Destroying Env::Default()\n");
239 exit(1);
240 }
241
242 virtual Status NewSequentialFile(const std::string& fname,
243 SequentialFile** result) {
244 FILE* f = fopen(fname.c_str(), "rb");
245 if (f == NULL) {
246 *result = NULL;
247 return Status::IOError(fname, strerror(errno));
248 } else {
249 *result = new ChromiumSequentialFile(fname, f);
250 return Status::OK();
251 }
252 }
253
254 virtual Status NewRandomAccessFile(const std::string& fname,
255 RandomAccessFile** result) {
256 int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
257 bool created;
258 ::base::PlatformFileError error_code;
259 ::base::PlatformFile file = ::base::CreatePlatformFile(
260 CreateFilePath(fname), flags, &created, &error_code);
261 if (error_code != ::base::PLATFORM_FILE_OK) {
262 *result = NULL;
263 return Status::IOError(fname, PlatformFileErrorString(error_code));
264 }
265 *result = new ChromiumRandomAccessFile(fname, file);
266 return Status::OK();
267 }
268
269 virtual Status NewWritableFile(const std::string& fname,
270 WritableFile** result) {
271 *result = NULL;
272 FILE* f = fopen(fname.c_str(), "wb");
273 if (f == NULL) {
274 return Status::IOError(fname, strerror(errno));
275 } else {
276 *result = new ChromiumWritableFile(fname, f);
277 return Status::OK();
278 }
279 }
280
281 virtual bool FileExists(const std::string& fname) {
282 return ::file_util::PathExists(CreateFilePath(fname));
283 }
284
285 virtual Status GetChildren(const std::string& dir,
286 std::vector<std::string>* result) {
287 result->clear();
288 ::file_util::FileEnumerator iter(
289 CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
290 ::FilePath current = iter.Next();
291 while (!current.empty()) {
292 result->push_back(FilePathToString(current.BaseName()));
293 current = iter.Next();
294 }
295 // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so
296 // we'll always return OK. Maybe manually check for error
297 // conditions like the file not existing?
298 return Status::OK();
299 }
300
301 virtual Status DeleteFile(const std::string& fname) {
302 Status result;
303 // TODO(jorlow): Should we assert this is a file?
304 if (!::file_util::Delete(CreateFilePath(fname), false)) {
305 result = Status::IOError(fname, "Could not delete file.");
306 }
307 return result;
308 };
309
310 virtual Status CreateDir(const std::string& name) {
311 Status result;
312 if (!::file_util::CreateDirectory(CreateFilePath(name))) {
313 result = Status::IOError(name, "Could not create directory.");
314 }
315 return result;
316 };
317
318 virtual Status DeleteDir(const std::string& name) {
319 Status result;
320 // TODO(jorlow): Should we assert this is a directory?
321 if (!::file_util::Delete(CreateFilePath(name), false)) {
322 result = Status::IOError(name, "Could not delete directory.");
323 }
324 return result;
325 };
326
327 virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
328 Status s;
329 int64_t signed_size;
330 if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) {
331 *size = 0;
332 s = Status::IOError(fname, "Could not determine file size.");
333 } else {
334 *size = static_cast<uint64_t>(signed_size);
335 }
336 return s;
337 }
338
339 virtual Status RenameFile(const std::string& src, const std::string& dst) {
340 Status result;
341 if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) {
342 result = Status::IOError(src, "Could not rename file.");
343 }
344 return result;
345 }
346
347 virtual Status LockFile(const std::string& fname, FileLock** lock) {
348 *lock = NULL;
349 Status result;
350 int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS |
351 ::base::PLATFORM_FILE_READ |
352 ::base::PLATFORM_FILE_WRITE |
353 ::base::PLATFORM_FILE_EXCLUSIVE_READ |
354 ::base::PLATFORM_FILE_EXCLUSIVE_WRITE;
355 bool created;
356 ::base::PlatformFileError error_code;
357 ::base::PlatformFile file = ::base::CreatePlatformFile(
358 CreateFilePath(fname), flags, &created, &error_code);
359 if (error_code != ::base::PLATFORM_FILE_OK) {
360 result = Status::IOError(fname, PlatformFileErrorString(error_code));
361 } else {
362 ChromiumFileLock* my_lock = new ChromiumFileLock;
363 my_lock->file_ = file;
364 *lock = my_lock;
365 }
366 return result;
367 }
368
369 virtual Status UnlockFile(FileLock* lock) {
370 ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
371 Status result;
372 if (!::base::ClosePlatformFile(my_lock->file_)) {
373 result = Status::IOError("Could not close lock file.");
374 }
375 delete my_lock;
376 return result;
377 }
378
379 virtual void Schedule(void (*function)(void*), void* arg);
380
381 virtual void StartThread(void (*function)(void* arg), void* arg);
382
383 virtual std::string UserIdentifier() {
384 #if defined(OS_WIN)
385 std::wstring user_sid;
386 bool ret = ::base::win::GetUserSidString(&user_sid);
387 DCHECK(ret);
388 return UTF16ToUTF8(user_sid);
389 #else
390 char buf[100];
391 snprintf(buf, sizeof(buf), "%d", int(geteuid()));
392 return buf;
393 #endif
394 }
395
396 virtual Status GetTestDirectory(std::string* path) {
397 mu_.Acquire();
398 if (test_directory_.empty()) {
399 if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
400 &test_directory_)) {
401 mu_.Release();
402 return Status::IOError("Could not create temp directory.");
403 }
404 }
405 *path = FilePathToString(test_directory_);
406 mu_.Release();
407 return Status::OK();
408 }
409
410 // TODO(user,user): Use Chromium's built-in logging?
411 static uint64_t gettid() {
412 uint64_t thread_id = 0;
413 // Coppied from base/logging.cc.
414 #if defined(OS_WIN)
415 thread_id = GetCurrentThreadId();
416 #elif defined(OS_MACOSX)
417 thread_id = mach_thread_self();
418 #elif defined(OS_LINUX)
419 thread_id = syscall(__NR_gettid);
420 #elif defined(OS_FREEBSD) || defined(OS_NACL)
421 // TODO(BSD): find a better thread ID
422 pthread_t tid = pthread_self();
423 memcpy(&thread_id, &tid, min(sizeof(r), sizeof(tid)));
424 #endif
425 return thread_id;
426 }
427
428 virtual Status NewLogger(const std::string& fname, Logger** result) {
429 FILE* f = fopen(fname.c_str(), "w");
430 if (f == NULL) {
431 *result = NULL;
432 return Status::IOError(fname, strerror(errno));
433 } else {
434 *result = new PosixLogger(f, &ChromiumEnv::gettid);
435 return Status::OK();
436 }
437 }
438
439 virtual int AppendLocalTimeToBuffer(char* buffer, size_t size) {
440 ::base::Time::Exploded t;
441 ::base::Time::Now().LocalExplode(&t);
442 return snprintf(buffer, size,
443 "%04d/%02d/%02d-%02d:%02d:%02d.%06d",
444 t.year,
445 t.month,
446 t.day_of_month,
447 t.hour,
448 t.minute,
449 t.second,
450 static_cast<int>(t.millisecond) * 1000);
451 }
452
453 virtual uint64_t NowMicros() {
454 return ::base::TimeTicks::HighResNow().ToInternalValue();
455 }
456
457 virtual void SleepForMicroseconds(int micros) {
458 // Round up to the next millisecond.
459 ::base::PlatformThread::Sleep((micros + 999) / 1000);
460 }
461
462 private:
463 // BGThread() is the body of the background thread
464 void BGThread();
465 static void BGThreadWrapper(void* arg) {
466 reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
467 }
468
469 FilePath test_directory_;
470
471 size_t page_size_;
472 ::base::Lock mu_;
473 ::base::ConditionVariable bgsignal_;
474 bool started_bgthread_;
475
476 // Entry per Schedule() call
477 struct BGItem { void* arg; void (*function)(void*); };
478 typedef std::deque<BGItem> BGQueue;
479 BGQueue queue_;
480 };
481
482 ChromiumEnv::ChromiumEnv()
483 : page_size_(::base::SysInfo::VMAllocationGranularity()),
484 bgsignal_(&mu_),
485 started_bgthread_(false) {
486 #if defined(OS_MACOSX)
487 ::base::EnableTerminationOnHeapCorruption();
488 ::base::EnableTerminationOnOutOfMemory();
489 #endif // OS_MACOSX
490 }
491
492 class Thread : public ::base::PlatformThread::Delegate {
493 public:
494 Thread(void (*function)(void* arg), void* arg)
495 : function_(function), arg_(arg) {
496 ::base::PlatformThreadHandle handle;
497 bool success = ::base::PlatformThread::Create(0, this, &handle);
498 DCHECK(success);
499 }
500 virtual ~Thread() {}
501 virtual void ThreadMain() {
502 (*function_)(arg_);
503 delete this;
504 }
505
506 private:
507 void (*function_)(void* arg);
508 void* arg_;
509 };
510
511 void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
512 mu_.Acquire();
513
514 // Start background thread if necessary
515 if (!started_bgthread_) {
516 started_bgthread_ = true;
517 StartThread(&ChromiumEnv::BGThreadWrapper, this);
518 }
519
520 // If the queue is currently empty, the background thread may currently be
521 // waiting.
522 if (queue_.empty()) {
523 bgsignal_.Signal();
524 }
525
526 // Add to priority queue
527 queue_.push_back(BGItem());
528 queue_.back().function = function;
529 queue_.back().arg = arg;
530
531 mu_.Release();
532 }
533
534 void ChromiumEnv::BGThread() {
535 while (true) {
536 // Wait until there is an item that is ready to run
537 mu_.Acquire();
538 while (queue_.empty()) {
539 bgsignal_.Wait();
540 }
541
542 void (*function)(void*) = queue_.front().function;
543 void* arg = queue_.front().arg;
544 queue_.pop_front();
545
546 mu_.Release();
547 (*function)(arg);
548 }
549 }
550
551 void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
552 new Thread(function, arg); // Will self-delete.
553 }
554
555 ::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
556 default_env(::base::LINKER_INITIALIZED);
557
558 }
559
560 Env* Env::Default() {
561 return default_env.Pointer();
562 }
563
564 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698