| 2180 | } |
| 2181 | |
| 2182 | func (f *VFSFile) Lock(elock sqlite3vfs.LockType) error { |
| 2183 | f.logger.Debug("locking file", "lock", elock) |
| 2184 | |
| 2185 | f.mu.Lock() |
| 2186 | defer f.mu.Unlock() |
| 2187 | |
| 2188 | if elock < f.lockType { |
| 2189 | return fmt.Errorf("invalid lock downgrade: current=%s target=%s", f.lockType, elock) |
| 2190 | } |
| 2191 | |
| 2192 | if elock >= sqlite3vfs.LockReserved { |
| 2193 | // Wait for any disable operation to complete before allowing RESERVED lock. |
| 2194 | // This prevents new write transactions from starting during disable. |
| 2195 | for f.disabling { |
| 2196 | f.logger.Debug("waiting for disable to complete before acquiring RESERVED lock") |
| 2197 | f.cond.Wait() |
| 2198 | } |
| 2199 | |
| 2200 | // Reject write-intent locks when writes are disabled. Since we always |
| 2201 | // report OpenReadWrite to SQLite (to support cold enable), SQLite may |
| 2202 | // attempt write transactions even when writes are logically disabled. |
| 2203 | if !f.writeEnabled { |
| 2204 | return sqlite3vfs.ReadOnlyError |
| 2205 | } |
| 2206 | } |
| 2207 | |
| 2208 | if f.writeEnabled && elock >= sqlite3vfs.LockReserved && !f.inTransaction { |
| 2209 | if f.vfs != nil { |
| 2210 | f.vfs.writeMu.Lock() |
| 2211 | if f.vfs.writeFile != nil && f.vfs.writeFile != f { |
| 2212 | f.vfs.writeMu.Unlock() |
| 2213 | return sqlite3vfs.BusyError |
| 2214 | } |
| 2215 | f.vfs.writeFile = f |
| 2216 | if f.vfs.lastSyncedTXID > f.expectedTXID && len(f.dirty) == 0 { |
| 2217 | f.expectedTXID = f.vfs.lastSyncedTXID |
| 2218 | f.pendingTXID = f.vfs.lastSyncedTXID + 1 |
| 2219 | f.pos = ltx.Pos{TXID: f.expectedTXID} |
| 2220 | } |
| 2221 | f.vfs.writeMu.Unlock() |
| 2222 | } |
| 2223 | f.inTransaction = true |
| 2224 | f.logger.Debug("transaction started", "expectedTXID", f.expectedTXID) |
| 2225 | } |
| 2226 | |
| 2227 | f.lockType = elock |
| 2228 | return nil |
| 2229 | } |
| 2230 | |
| 2231 | func (f *VFSFile) Unlock(elock sqlite3vfs.LockType) error { |
| 2232 | f.logger.Debug("unlocking file", "lock", elock) |