1 // Copyright 2019 The Chromium 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. 4 5 #include "sql/vfs_wrapper_fuchsia.h" 6 7 #include "base/containers/flat_set.h" 8 #include "base/no_destructor.h" 9 #include "base/synchronization/lock.h" 10 #include "base/thread_annotations.h" 11 #include "sql/vfs_wrapper.h" 12 13 namespace sql { 14 15 namespace { 16 17 // Singleton that stores locks state. 18 class FuchsiaFileLockManager { 19 public: 20 FuchsiaFileLockManager() = default; 21 22 // Returns lock manager for the current process. Instance()23 static FuchsiaFileLockManager* Instance() { 24 static base::NoDestructor<FuchsiaFileLockManager> lock_manager; 25 return lock_manager.get(); 26 } 27 28 // Return true if the file was locked successfully. Lock(const std::string & name)29 bool Lock(const std::string& name) { 30 base::AutoLock lock(lock_); 31 32 if (locked_files_.find(name) != locked_files_.end()) { 33 DLOG(WARNING) << "File " << name 34 << " is being used concurrently by multiple consumers."; 35 return false; 36 } 37 38 locked_files_.insert(name); 39 return true; 40 } 41 Unlock(const std::string & name)42 void Unlock(const std::string& name) { 43 base::AutoLock lock(lock_); 44 45 size_t removed = locked_files_.erase(name); 46 DCHECK_EQ(removed, 1U); 47 } 48 IsLocked(const std::string & name)49 bool IsLocked(const std::string& name) { 50 base::AutoLock lock(lock_); 51 return locked_files_.find(name) != locked_files_.end(); 52 } 53 54 private: 55 ~FuchsiaFileLockManager() = delete; 56 57 base::Lock lock_; 58 59 // Set of all currently locked files. 60 base::flat_set<std::string> locked_files_ GUARDED_BY(lock_); 61 }; 62 63 } // namespace 64 FuchsiaVfsLock(sqlite3_file * sqlite_file,int file_lock)65int FuchsiaVfsLock(sqlite3_file* sqlite_file, int file_lock) { 66 DCHECK(file_lock == SQLITE_LOCK_SHARED || file_lock == SQLITE_LOCK_RESERVED || 67 file_lock == SQLITE_LOCK_PENDING || 68 file_lock == SQLITE_LOCK_EXCLUSIVE); 69 70 VfsFile* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file); 71 72 if (vfs_file->lock_level == SQLITE_LOCK_NONE) { 73 if (!FuchsiaFileLockManager::Instance()->Lock(vfs_file->file_name)) 74 return SQLITE_BUSY; 75 } 76 77 vfs_file->lock_level = file_lock; 78 79 return SQLITE_OK; 80 } 81 FuchsiaVfsUnlock(sqlite3_file * sqlite_file,int file_lock)82int FuchsiaVfsUnlock(sqlite3_file* sqlite_file, int file_lock) { 83 VfsFile* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file); 84 85 if (file_lock == SQLITE_LOCK_NONE) { 86 if (vfs_file->lock_level != SQLITE_LOCK_NONE) 87 FuchsiaFileLockManager::Instance()->Unlock(vfs_file->file_name); 88 } else { 89 // Keep the file locked for the shared lock. 90 DCHECK(file_lock == SQLITE_LOCK_SHARED); 91 DCHECK(FuchsiaFileLockManager::Instance()->IsLocked(vfs_file->file_name)); 92 } 93 vfs_file->lock_level = file_lock; 94 95 return SQLITE_OK; 96 } 97 FuchsiaVfsCheckReservedLock(sqlite3_file * sqlite_file,int * result)98int FuchsiaVfsCheckReservedLock(sqlite3_file* sqlite_file, int* result) { 99 VfsFile* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file); 100 return vfs_file->lock_level; 101 } 102 103 } // namespace sql 104