blob: 4f546d51917c77b15e94436281c4aff821a55771 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SQLITE_VFS_SHARED_LOCKS_H_
#define COMPONENTS_SQLITE_VFS_SHARED_LOCKS_H_
#include <stdint.h>
#include <optional>
#include "base/component_export.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/shared_memory_safety_checker.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "components/sqlite_vfs/lock_state.h"
namespace sqlite_vfs {
// Manages the set of cross-connection (within or across processes) locks for
// a SQLite database.
//
// Each database that supports multiple connections requires that each
// connection use the same set of shared locks to coordinate access. A database
// using a rollback journal requires only the primary database lock. This is
// the only supported scenario at present.
//
// TODO(crbug.com/486665177): Add the eight WAL locks to support multiple
// connections for databases that use a write-ahead log.
class COMPONENT_EXPORT(SQLITE_VFS) SharedLocks {
public:
// Returns a new unmapped shared memory region sized appropriately to hold
// the shared locks.
static base::UnsafeSharedMemoryRegion CreateRegion();
// Maps `region` and returns a SharedLocks object backed by it. Returns no
// value in case of failure to map `region` into the process's address space.
static std::optional<SharedLocks> Create(
const base::UnsafeSharedMemoryRegion& region);
SharedLocks(const SharedLocks&) = delete;
SharedLocks& operator=(const SharedLocks&) = delete;
SharedLocks(SharedLocks&&) = default;
SharedLocks& operator=(SharedLocks&&) = default;
~SharedLocks();
// Lock operations on the primary database lock corresponding to SQLite file
// operations; see https://sqlite.org/c3ref/io_methods.html.
// Attempts to raise the lock from `current_mode` to `mode`, writing the new
// mode into `current_mode` and returning `SQLITE_OK` on success. Returns a
// SQLite error code on failure, in which case `current_mode` may have been
// modified (e.g., an attempt to acquire an exclusive lock may acquire a
// pending lock before failing with SQLITE_BUSY). Returns `SQLITE_IOERR_LOCK`
// if the locks have been abandoned.
int Lock(int mode, int& current_mode);
// Lowers the lock from a higher level down to `mode`, which must be either
// `SQLITE_LOCK_SHARED` or `SQLITE_LOCK_NONE`. Sets `current_mode` to `mode`
// and returns `SQLITE_OK`.
int Unlock(int mode, int& current_mode);
// Returns true if any connection holds the reserved lock.
bool IsReserved();
// Marks the locks as abandoned, causing all subsequent attempts to raise the
// primary database lock to a higher level by any party to fail with
// `SQLITE_IOERR_LOCK`. Returns the state of the primary database lock at the
// time of abandonment. Determination of this state is made based on a
// snapshot of the lock at the moment that the lock is abandoned. This is the
// only point where it is possible to know the state of the lock owing to the
// nature of atomic bitwise operations on the lock itself; the lock level may
// be raised to pending or reserved after abandonment, although the callers
// requesting such will properly detect that the lock has been abandoned.
LockState Abandon();
private:
// Creates a new SharedLocks object backed by the given mapping, which must
// have been created via `CreateRegion()`.
explicit SharedLocks(base::WritableSharedMemoryMapping mapping);
// Returns the atomic for the primary database lock.
using DatabaseLock = base::subtle::SharedAtomic<uint32_t>;
DatabaseLock& GetDatabaseLock();
base::WritableSharedMemoryMapping mapping_;
};
} // namespace sqlite_vfs
#endif // COMPONENTS_SQLITE_VFS_SHARED_LOCKS_H_