// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sql/vfs_wrapper_fuchsia.h" #include "base/containers/flat_set.h" #include "base/no_destructor.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "sql/vfs_wrapper.h" namespace sql { namespace { // Singleton that stores locks state. class FuchsiaFileLockManager { public: FuchsiaFileLockManager() = default; // Returns lock manager for the current process. static FuchsiaFileLockManager* Instance() { static base::NoDestructor lock_manager; return lock_manager.get(); } // Return true if the file was locked successfully. bool Lock(const std::string& name) { base::AutoLock lock(lock_); if (locked_files_.find(name) != locked_files_.end()) { DLOG(WARNING) << "File " << name << " is being used concurrently by multiple consumers."; return false; } locked_files_.insert(name); return true; } void Unlock(const std::string& name) { base::AutoLock lock(lock_); size_t removed = locked_files_.erase(name); DCHECK_EQ(removed, 1U); } bool IsLocked(const std::string& name) { base::AutoLock lock(lock_); return locked_files_.find(name) != locked_files_.end(); } private: ~FuchsiaFileLockManager() = delete; base::Lock lock_; // Set of all currently locked files. base::flat_set locked_files_ GUARDED_BY(lock_); }; } // namespace int FuchsiaVfsLock(sqlite3_file* sqlite_file, int file_lock) { DCHECK(file_lock == SQLITE_LOCK_SHARED || file_lock == SQLITE_LOCK_RESERVED || file_lock == SQLITE_LOCK_PENDING || file_lock == SQLITE_LOCK_EXCLUSIVE); VfsFile* vfs_file = reinterpret_cast(sqlite_file); if (vfs_file->lock_level == SQLITE_LOCK_NONE) { if (!FuchsiaFileLockManager::Instance()->Lock(vfs_file->file_name)) return SQLITE_BUSY; } vfs_file->lock_level = file_lock; return SQLITE_OK; } int FuchsiaVfsUnlock(sqlite3_file* sqlite_file, int file_lock) { VfsFile* vfs_file = reinterpret_cast(sqlite_file); if (file_lock == SQLITE_LOCK_NONE) { if (vfs_file->lock_level != SQLITE_LOCK_NONE) FuchsiaFileLockManager::Instance()->Unlock(vfs_file->file_name); } else { // Keep the file locked for the shared lock. DCHECK(file_lock == SQLITE_LOCK_SHARED); DCHECK(FuchsiaFileLockManager::Instance()->IsLocked(vfs_file->file_name)); } vfs_file->lock_level = file_lock; return SQLITE_OK; } int FuchsiaVfsCheckReservedLock(sqlite3_file* sqlite_file, int* result) { VfsFile* vfs_file = reinterpret_cast(sqlite_file); return vfs_file->lock_level; } } // namespace sql