vfs_wrapper_fuchsia.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. #include "sql/vfs_wrapper_fuchsia.h"
  5. #include "base/check_op.h"
  6. #include "base/containers/fixed_flat_set.h"
  7. #include "base/containers/flat_map.h"
  8. #include "base/containers/flat_set.h"
  9. #include "base/logging.h"
  10. #include "base/no_destructor.h"
  11. #include "base/notreached.h"
  12. #include "base/synchronization/lock.h"
  13. #include "base/thread_annotations.h"
  14. #include "sql/vfs_wrapper.h"
  15. namespace sql {
  16. namespace {
  17. struct FileLock {
  18. int lock_level;
  19. // Used to track the pointers to different VfsFile instances that hold shared
  20. // locks on the same underlying file. The pointer is only used as a unique id
  21. // for the VfsFile instance. The contents are never accessed.
  22. base::flat_set<VfsFile*> readers = {};
  23. // Used to track a VfsFile instance that holds a reserved/pending/exclusive
  24. // lock for writing. The pointer is only used as a unique id for the VfsFile
  25. // instance. The contents are never accessed.
  26. VfsFile* writer = nullptr;
  27. };
  28. // Singleton that stores and mutates state as described in
  29. // https://www.sqlite.org/lockingv3.html
  30. class FuchsiaFileLockManager {
  31. public:
  32. FuchsiaFileLockManager() = default;
  33. // Returns lock manager for the current process.
  34. static FuchsiaFileLockManager* Instance() {
  35. static base::NoDestructor<FuchsiaFileLockManager> lock_manager;
  36. return lock_manager.get();
  37. }
  38. int Lock(VfsFile* vfs_file, int requested_lock) {
  39. DCHECK_GT(requested_lock, SQLITE_LOCK_NONE)
  40. << "SQLITE_LOCK_NONE can only be set via Unlock";
  41. base::AutoLock lock(lock_);
  42. const auto file_lock_state = GetFileLockStateLocked(vfs_file);
  43. // Allow any lock level since the lock isn't held.
  44. if (file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
  45. if (requested_lock == SQLITE_LOCK_SHARED) {
  46. locked_files_[vfs_file->file_name] = {.lock_level = requested_lock,
  47. .readers = {vfs_file}};
  48. } else {
  49. locked_files_[vfs_file->file_name] = {.lock_level = requested_lock,
  50. .writer = vfs_file};
  51. }
  52. return SQLITE_OK;
  53. }
  54. if (requested_lock == SQLITE_LOCK_SHARED) {
  55. if (file_lock_state.lock_level >= SQLITE_LOCK_PENDING) {
  56. DVLOG(1) << "lock for file " << vfs_file->file_name
  57. << " is held by a writer and cannot be shared.";
  58. return SQLITE_BUSY;
  59. }
  60. locked_files_[vfs_file->file_name].readers.insert(vfs_file);
  61. return SQLITE_OK;
  62. }
  63. if (file_lock_state.writer != nullptr &&
  64. file_lock_state.writer != vfs_file) {
  65. DVLOG(1) << "lock for file " << vfs_file->file_name
  66. << " is already held by another writer.";
  67. return SQLITE_BUSY;
  68. }
  69. if (requested_lock == SQLITE_LOCK_EXCLUSIVE &&
  70. (file_lock_state.readers.size() > 1 ||
  71. (file_lock_state.readers.size() == 1 &&
  72. !file_lock_state.readers.contains(vfs_file)))) {
  73. DVLOG(1) << "lock for file " << vfs_file->file_name
  74. << " is held by readers and can't yet be upgraded to exclusive.";
  75. return SQLITE_BUSY;
  76. }
  77. DCHECK(file_lock_state.writer == nullptr ||
  78. file_lock_state.writer == vfs_file);
  79. locked_files_[vfs_file->file_name].lock_level = requested_lock;
  80. locked_files_[vfs_file->file_name].writer = vfs_file;
  81. locked_files_[vfs_file->file_name].readers.erase(vfs_file);
  82. DCHECK(locked_files_[vfs_file->file_name].lock_level <
  83. SQLITE_LOCK_EXCLUSIVE ||
  84. locked_files_[vfs_file->file_name].readers.empty());
  85. return SQLITE_OK;
  86. }
  87. int Unlock(VfsFile* vfs_file, int requested_lock) {
  88. base::AutoLock lock(lock_);
  89. const auto file_lock_state = GetFileLockStateLocked(vfs_file);
  90. DCHECK_LE(requested_lock, file_lock_state.lock_level)
  91. << "Attempted to unlock to a higher lock level, unlock can only "
  92. "decrement.";
  93. // Shortcut if the caller doesn't currently hold a lock.
  94. if (!file_lock_state.readers.contains(vfs_file) &&
  95. file_lock_state.writer != vfs_file) {
  96. DVLOG(1) << "caller can't unlock because it doesn't currently "
  97. << "hold a lock for file " << vfs_file->file_name;
  98. return SQLITE_OK;
  99. }
  100. if (requested_lock == SQLITE_LOCK_NONE) {
  101. locked_files_[vfs_file->file_name].readers.erase(vfs_file);
  102. } else if (requested_lock == SQLITE_LOCK_SHARED) {
  103. locked_files_[vfs_file->file_name].readers.insert(vfs_file);
  104. }
  105. if (requested_lock < SQLITE_LOCK_RESERVED &&
  106. file_lock_state.writer == vfs_file) {
  107. locked_files_[vfs_file->file_name].writer = nullptr;
  108. }
  109. // Check that `vfs_file` is correctly tracked given the `requested_lock`.
  110. DCHECK(requested_lock == SQLITE_LOCK_SHARED ||
  111. !locked_files_[vfs_file->file_name].readers.contains(vfs_file));
  112. DCHECK_EQ(requested_lock > SQLITE_LOCK_SHARED,
  113. locked_files_[vfs_file->file_name].writer == vfs_file);
  114. // Mark lock level as shared if there are only shared usages.
  115. if (!file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
  116. locked_files_[vfs_file->file_name].lock_level = SQLITE_LOCK_SHARED;
  117. return SQLITE_OK;
  118. }
  119. // Remove lock if there are no usages left.
  120. if (file_lock_state.readers.empty() && file_lock_state.writer == nullptr) {
  121. DCHECK_EQ(requested_lock, SQLITE_LOCK_NONE);
  122. locked_files_.erase(vfs_file->file_name);
  123. return SQLITE_OK;
  124. }
  125. if (file_lock_state.writer != vfs_file) {
  126. DCHECK_GE(file_lock_state.lock_level, SQLITE_LOCK_RESERVED);
  127. DCHECK_LE(requested_lock, SQLITE_LOCK_SHARED);
  128. return SQLITE_OK;
  129. }
  130. locked_files_[vfs_file->file_name].lock_level = requested_lock;
  131. return SQLITE_OK;
  132. }
  133. int CheckReservedLock(VfsFile* vfs_file, int* result) {
  134. base::AutoLock lock(lock_);
  135. const auto file_lock_state = GetFileLockStateLocked(vfs_file);
  136. switch (file_lock_state.lock_level) {
  137. case SQLITE_LOCK_NONE:
  138. case SQLITE_LOCK_SHARED:
  139. *result = 0;
  140. return SQLITE_OK;
  141. case SQLITE_LOCK_RESERVED:
  142. case SQLITE_LOCK_PENDING:
  143. case SQLITE_LOCK_EXCLUSIVE:
  144. *result = 1;
  145. return SQLITE_OK;
  146. default:
  147. return SQLITE_IOERR_CHECKRESERVEDLOCK;
  148. }
  149. }
  150. private:
  151. ~FuchsiaFileLockManager() = delete;
  152. const FileLock& GetFileLockStateLocked(VfsFile* vfs_file)
  153. EXCLUSIVE_LOCKS_REQUIRED(lock_) {
  154. static const FileLock kUnlockedFileLock = {.lock_level = SQLITE_LOCK_NONE};
  155. const auto file_lock_state_iter = locked_files_.find(vfs_file->file_name);
  156. if (file_lock_state_iter == locked_files_.end()) {
  157. return kUnlockedFileLock;
  158. }
  159. return file_lock_state_iter->second;
  160. }
  161. base::Lock lock_;
  162. // Set of all currently locked files.
  163. base::flat_map<std::string, FileLock> locked_files_ GUARDED_BY(lock_);
  164. };
  165. } // namespace
  166. int Lock(sqlite3_file* sqlite_file, int file_lock) {
  167. DCHECK(file_lock == SQLITE_LOCK_SHARED || file_lock == SQLITE_LOCK_RESERVED ||
  168. file_lock == SQLITE_LOCK_PENDING ||
  169. file_lock == SQLITE_LOCK_EXCLUSIVE);
  170. auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
  171. return FuchsiaFileLockManager::Instance()->Lock(vfs_file, file_lock);
  172. }
  173. int Unlock(sqlite3_file* sqlite_file, int file_lock) {
  174. auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
  175. return FuchsiaFileLockManager::Instance()->Unlock(vfs_file, file_lock);
  176. }
  177. int CheckReservedLock(sqlite3_file* sqlite_file, int* result) {
  178. auto* vfs_file = reinterpret_cast<VfsFile*>(sqlite_file);
  179. return FuchsiaFileLockManager::Instance()->CheckReservedLock(vfs_file,
  180. result);
  181. }
  182. } // namespace sql