| 2229 | } |
| 2230 | |
| 2231 | func (f *VFSFile) Unlock(elock sqlite3vfs.LockType) error { |
| 2232 | f.logger.Debug("unlocking file", "lock", elock) |
| 2233 | |
| 2234 | f.mu.Lock() |
| 2235 | defer f.mu.Unlock() |
| 2236 | |
| 2237 | if elock != sqlite3vfs.LockShared && elock != sqlite3vfs.LockNone { |
| 2238 | return fmt.Errorf("invalid unlock target: %s", elock) |
| 2239 | } |
| 2240 | |
| 2241 | if f.writeEnabled && f.inTransaction && elock < sqlite3vfs.LockReserved { |
| 2242 | f.inTransaction = false |
| 2243 | if f.vfs != nil { |
| 2244 | f.vfs.writeMu.Lock() |
| 2245 | if f.vfs.writeFile == f { |
| 2246 | f.vfs.writeFile = nil |
| 2247 | } |
| 2248 | f.vfs.writeMu.Unlock() |
| 2249 | } |
| 2250 | f.logger.Debug("transaction ended", "dirtyPages", len(f.dirty)) |
| 2251 | f.cond.Broadcast() // Wake up SetWriteEnabledWithTimeout if waiting |
| 2252 | } |
| 2253 | |
| 2254 | f.lockType = elock |
| 2255 | |
| 2256 | // Copy pending index to main index and invalidate affected pages in cache. |
| 2257 | if f.pendingReplace { |
| 2258 | // Replace entire index |
| 2259 | count := len(f.index) |
| 2260 | f.index = f.pending |
| 2261 | f.logger.Debug("cache invalidated all pages", "count", count) |
| 2262 | // Invalidate entire cache since we replaced the index |
| 2263 | f.cache.Purge() |
| 2264 | } else if len(f.pending) > 0 { |
| 2265 | // Merge pending into index |
| 2266 | count := len(f.pending) |
| 2267 | for k, v := range f.pending { |
| 2268 | f.index[k] = v |
| 2269 | f.cache.Remove(k) |
| 2270 | } |
| 2271 | f.logger.Debug("cache invalidated pages", "count", count) |
| 2272 | } |
| 2273 | f.pending = make(map[uint32]ltx.PageIndexElem) |
| 2274 | f.pendingReplace = false |
| 2275 | |
| 2276 | return nil |
| 2277 | } |
| 2278 | |
| 2279 | func (f *VFSFile) CheckReservedLock() (bool, error) { |
| 2280 | f.logger.Debug("checking reserved lock") |