@rapidrabbit/gitdb
Version:
A powerful, flexible database module for storing data in various formats with local file and GitHub storage options
97 lines (84 loc) • 2.19 kB
JavaScript
/**
* LockManager - Handles file locking for concurrent access control
*/
const fs = require('fs').promises
const path = require('path')
class LockManager {
constructor (options = {}) {
this.lockFile = options.lockFile || '.db.lock'
this.repoPath = options.repoPath || './data'
this.maxRetries = options.maxRetries || 3
this.retryDelay = options.retryDelay || 1000
this.lockTimeout = options.lockTimeout || 30000 // 30 seconds
}
/**
* Initialize lock manager
*/
async initialize () {
// No initialization needed for lock manager
}
/**
* Acquire a lock
*/
async acquireLock () {
const lockPath = path.join(this.repoPath, this.lockFile)
let retries = 0
while (retries < this.maxRetries) {
try {
await fs.writeFile(lockPath, Date.now().toString(), { flag: 'wx' })
return true
} catch (error) {
if (error.code === 'EEXIST') {
try {
const lockContent = await fs.readFile(lockPath, 'utf8')
const lockTime = parseInt(lockContent)
const now = Date.now()
if (now - lockTime > this.lockTimeout) {
await this.releaseLock()
continue
}
} catch {
try {
await fs.unlink(lockPath)
} catch {}
continue
}
}
retries++
if (retries < this.maxRetries) {
await this.sleep(this.retryDelay * retries)
}
}
}
throw new Error('Failed to acquire lock after maximum retries')
}
/**
* Release the lock
*/
async releaseLock () {
const lockPath = path.join(this.repoPath, this.lockFile)
try {
await fs.unlink(lockPath)
} catch (error) {
// Ignore errors when releasing lock
}
}
/**
* Sleep utility function
*/
sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* Get lock configuration
*/
getConfig () {
return {
lockFile: this.lockFile,
maxRetries: this.maxRetries,
retryDelay: this.retryDelay,
lockTimeout: this.lockTimeout
}
}
}
module.exports = { LockManager }